2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: Layout.c /main/31 1996/10/25 12:00:15 cde-hp $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: CDE Info System
31 ** Description: Lays out the information on a canvas.
33 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
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.
41 ****************************************************************************
42 ************************************<+>*************************************/
53 * Canvas Engine includes
56 #include "CanvasSegP.h"
63 #include "CvStringI.h"
64 #include "LayoutUtilI.h"
65 #include "SelectionI.h"
66 #include "VirtFuncsI.h"
72 /******************************************************************************
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)
87 #define CheckAddToHyperList(a, b) \
88 _DtCvCheckAddHyperToTravList(a, b, _DtCvTRUE, \
89 &(layout->info.lst_vis), \
90 &(layout->info.lst_hyper), &(layout->info.cur_len))
92 /*****************************************************************************
94 *****************************************************************************/
96 * Defines for the dimension arrays
102 #define DIMS_CENTER 1
106 #define DIMS_BOTTOM 2
109 #define DIMS_HEIGHT 1
120 /******************************************************************************
124 *****************************************************************************/
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 * |-------------|-------------|-------------|/|/ |
136 * |-------------|-------------|-------------|/|/
137 * DIMS_BOTTOM | DIMS_LM | DIMS_CENTER | DIMS_RM | /
138 * ------------------------------------------|/
140 typedef _DtCvUnit TopDims[DIMS_BOTTOM+1][DIMS_RM+1][DIMS_HEIGHT+1];
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 * ----------------------------
152 typedef _DtCvUnit SideDims[DIMS_BOTTOM+1][DIMS_RIGHT+1];
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 * ----------------------------
162 typedef _DtCvUnit CornerDims[DIMS_BC+1][DIMS_RIGHT+1];
165 * flow dimension array
166 * -------------|--------------
167 * DIMS_LEFT | DIMS_WIDTH | DIMS_HEIGHT |
169 * |------------|-------------|
170 * DIMS_RIGHT | DIMS_WIDTH | DIMS_HEIGHT |
172 * ----------------------------
174 typedef _DtCvUnit FlowDims[DIMS_RIGHT+1][DIMS_HEIGHT+1];
177 * margin data - important for determining flowing
179 typedef struct _dataPoint {
184 struct _dataPoint *next_pt;
190 typedef struct _cntInfo {
203 typedef struct _grpInfo {
209 struct _grpInfo *next_info;
213 * layout information per container
215 typedef struct _layFrmtInfo {
219 struct _layFrmtInfo *next_info;
223 * the layout information carried around
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;
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
249 _DtCvSegmentI *lst_rendered; /* indicates the last string/region */
250 char *target_id; /* if non-null, the id to search for */
252 GrpInfo *grp_lst; /* list of groups */
253 _DtCvLayoutInfo info;
257 * information for laying out cells in a table.
264 _DtCvSegmentI *cell_seg;
268 * column description information for a table.
270 typedef struct _columnSpec {
275 _DtCvFrmtOption justify;
279 * row description information
281 typedef struct _rowSpec {
285 _DtCvUnit lst_height;
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}};
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; */
322 static const DataPoint DefDataPt = { 0, 0, _CEFORMAT_ALL, 0, NULL};
324 static const double HeadDivisor = 10000.0;
326 static const char *PeriodStr = ".";
328 static const char *DefWidth[2] = { "", NULL };
330 static const _DtCvSegmentI BlankTableCell =
332 _DtCvCONTAINER, /* type */
334 { /* container info */
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 */
351 _DtCvBORDER_NONE, /* bdr_info */
355 NULL, /* next_disp */
356 NULL, /* client_use */
357 NULL /* internal_use */
360 /*****************************************************************************
361 * Private Function Declarations
362 *****************************************************************************/
363 static void AdjustForBorders(
364 _DtCanvasStruct *canvas,
366 _DtCvFrmtOption brdr,
367 _DtCvUnit line_width,
369 _DtCvUnit *ret_right);
370 static void AdjustHeadPosition(
371 _DtCanvasStruct *canvas,
373 _DtCvSegmentI *p_seg,
381 _DtCvUnit block_width,
382 _DtCvUnit left_margin,
383 _DtCvUnit right_margin);
384 static void AdjustObjectPosition(
385 _DtCanvasStruct *canvas,
387 _DtCvFrmtOption justify,
395 _DtCvUnit height_adj,
398 _DtCvUnit internal_y);
399 static void CheckSaveInfo (
400 _DtCanvasStruct *canvas,
402 _DtCvSegmentI *new_seg,
404 static void DetermineFlowConstraints(
407 _DtCvUnit left_margin,
408 _DtCvUnit right_margin,
411 DataPoint *right_pt);
412 static void DetermineHeadPositioning(
419 _DtCvUnit block_size,
420 _DtCvUnit *ret_side_size);
421 static void DetermineMaxDims(
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,
432 _DtCvFrmtOption brdr,
434 _DtCvUnit line_width,
439 static void FormatCell(
440 _DtCanvasStruct *canvas,
442 _DtCvSegmentI *cell_seg,
443 _DtCvUnit span_width,
444 _DtCvUnit min_height,
447 _DtCvUnit *ret_width,
448 _DtCvUnit *ret_height,
449 _DtCvValue *ret_tab_flag);
450 static void InitDimArrays(
455 static _DtCvStatus LayoutCanvasInfo (
456 _DtCanvasStruct *canvas,
460 static _DtCvValue LinesMayChange(
461 _DtCanvasStruct *canvas,
465 static _DtCvUnit MoveGroup (
466 _DtCanvasStruct *canvas,
470 static _DtCvUnit MoveLines (
471 _DtCanvasStruct *canvas,
477 static _DtCvUnit MoveText (
478 _DtCanvasStruct *canvas,
484 static void ProcessContainer(
485 _DtCanvasStruct *canvas,
487 _DtCvSegmentI *con_seg,
489 _DtCvUnit *ret_width,
490 _DtCvUnit *ret_max_x,
492 static void ProcessSegmentList(
493 _DtCanvasStruct *canvas,
495 _DtCvSegmentI *cur_seg,
497 _DtCvUnit *ret_width,
498 _DtCvUnit *ret_max_x,
501 /******************************************************************************
505 *****************************************************************************/
506 /******************************************************************************
507 * Function: AdjustTextPositions
509 * changes the baseline and text_x positioning of the text line by the
511 *****************************************************************************/
514 _DtCanvasStruct *canvas,
520 if ( 0 != y_offset || 0 != x_offset)
524 canvas->txt_lst[beg].baseline += y_offset;
525 canvas->txt_lst[beg].text_x += x_offset;
531 /******************************************************************************
532 * Function: AdjustLinePositions
534 * changes the x & positions and the max x & y values by the offsets indicated.
535 *****************************************************************************/
538 _DtCanvasStruct *canvas,
544 if ( 0 != y_offset || 0 != x_offset)
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;
558 /******************************************************************************
559 * Function: AdjustPgBrk
561 * changes the y position of a page break.
562 *****************************************************************************/
565 _DtCanvasStruct *canvas,
573 canvas->pg_breaks[beg++] += y_offset;
577 /******************************************************************************
578 * Function: MaxXOfLine
580 * MaxXOfLine determines the max X of a line segment.
582 *****************************************************************************/
583 /******************************************************************************
584 * Function: MaxXOfLine
586 * MaxXOfLine determines the max X of a line segment.
588 *****************************************************************************/
591 _DtCanvasStruct *canvas,
594 _DtCvValue lastLinkVisible = FALSE;
595 int count = line->length;
596 int start = line->byte_index;
603 xPos = _DtCvGetStartXOfLine(line, &pSeg);
605 while (pSeg != NULL && count > 0)
607 xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
608 &lnkInd, &lastLinkVisible);
610 _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
611 &len, &tmpWidth, NULL);
615 pSeg = pSeg->next_disp;
620 } /* End MaxXOfLine */
622 /*****************************************************************************
623 * Function: void GetLinkInfo ()
626 * canvas Specifies the handle for the canvas.
628 * Returns: A handle to the canvas or NULL if an error occurs.
632 *****************************************************************************/
635 _DtCvHandle canvas_handle,
639 _DtCvUnit *ret_width,
640 _DtCvUnit *ret_height)
648 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
650 _DtCvValue lstVisible = False;
651 _DtCvValue found = False;
659 line = canvas->trav_lst[indx].idx;
662 * get some information from the line
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;
671 while (count > 0 && !found && pSeg != NULL)
673 if (startX < canvas->txt_lst[line].text_x)
674 startX = canvas->txt_lst[line].text_x;
677 * adjust the starting position by the link space
679 junk = _DtCvIsSegVisibleLink(pSeg);
680 lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg, junk,
681 lstVisible, lnkIndx, &startX);
683 * adjust the starting position by the traversal space
685 junk = _DtCvIsSegALink(pSeg);
686 (void) _DtCvModifyXpos (canvas->traversal_info, pSeg, junk,
687 ((_DtCvValue) True), lnkIndx, &startX);
689 lnkIndx = pSeg->link_idx;
694 if (_DtCvIsSegNoop(pSeg))
700 else if (_DtCvIsSegRegion(pSeg))
703 endX = startX + _DtCvWidthOfRegionSeg(pSeg);
708 * initialize the pointer to the string
710 pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
711 _DtCvIsSegWideChar(pSeg), startChar);
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.
720 len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
725 * calculate the ending pixel postion for
726 * this string segment.
728 endX = startX + _DtCvGetStringWidth(canvas,pSeg,pChar,len);
733 * test to see if the selected segment was this segment.
735 if (pSeg == canvas->trav_lst[indx].seg_ptr)
739 *ret_width = endX - startX;
744 * go to the next segment.
746 pSeg = pSeg->next_disp;
749 * adjust for the new begining.
759 /******************************************************************************
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 *****************************************************************************/
770 if (layout->target_id != NULL && NULL != id &&
771 _DtCvStrCaseCmpLatin1(id, layout->target_id) == 0)
773 layout->id_Ypos = layout->info.y_pos;
774 layout->id_found = True;
778 /******************************************************************************
779 * Function: CheckSetLineStart
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 *****************************************************************************/
787 _DtCvSegmentI *cur_seg)
789 if (layout->info.line_bytes == 0)
791 layout->info.line_seg = cur_seg;
792 layout->info.line_start = 0;
796 /******************************************************************************
797 * Function: CheckForPageBreak
799 * Check to see if there is a page break on this segment.
800 * If so, remember its position.
801 *****************************************************************************/
804 _DtCanvasStruct *canvas,
805 _DtCvSegmentI *cur_seg,
809 * does this segment cause a page break?
811 if (_DtCvIsSegPageBreak(cur_seg))
814 * check to see if there is room to save the page break.
815 * if not, allocate more room.
817 if (canvas->brk_cnt >= canvas->brk_max)
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));
825 canvas->pg_breaks = (_DtCvUnit *) malloc (
826 (sizeof(_DtCvUnit) * canvas->brk_max));
830 * failed to allocate memory, abort.
832 if (NULL == canvas->pg_breaks)
840 * save the y position of the page break for later.
842 canvas->pg_breaks[canvas->brk_cnt++] = position;
848 /******************************************************************************
849 * Function: SetBeginCounts
852 * canvas Specifies the canvas.
853 * f_info Specifies the layout count info.
857 * Purpose: Initializes the layout count information for a container.
858 *****************************************************************************/
861 _DtCanvasStruct *canvas,
867 cnt_info->beg_txt = canvas->txt_cnt;
868 cnt_info->end_txt = canvas->txt_cnt;
873 cnt_info->beg_ln = canvas->line_cnt;
874 cnt_info->end_ln = canvas->line_cnt;
879 cnt_info->beg_brk = canvas->brk_cnt;
880 cnt_info->end_brk = canvas->brk_cnt;
883 /******************************************************************************
884 * Function: SetEndCounts
887 * canvas Specifies the canvas.
888 * f_info Specifies the layout count info.
892 * Purpose: Sets the ending layout counts for a container.
893 *****************************************************************************/
896 _DtCanvasStruct *canvas,
903 cnt_info->end_txt = canvas->txt_cnt;
908 cnt_info->end_ln = canvas->line_cnt;
913 cnt_info->end_brk = canvas->brk_cnt;
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.
920 cnt_info->my_lines = end_ln;
923 /******************************************************************************
924 * Function: SkipToNumber
927 *****************************************************************************/
934 const char *str = *string;
936 while (*str == ' ' && *str != '\0')
942 /******************************************************************************
943 * Function: GetValueFromString
946 *****************************************************************************/
954 if (string != NULL && *string != NULL && **string != '\0')
956 const char *str = *string;
958 if ('0' <= *str && *str <= '9')
961 while ('0' <= *str && *str <= '9')
964 while (*str != ' ' && *str != '\0' && (*str < '0' || *str > '9'))
973 /******************************************************************************
974 * Function: PushDataPoint
977 *****************************************************************************/
983 data_pt->x_units = 0;
984 data_pt->next_pt = layout->data_pts;
985 layout->data_pts = data_pt;
988 /******************************************************************************
989 * Function: InsertDataPoint
992 *****************************************************************************/
998 DataPoint *lastPt = NULL;
999 DataPoint *nextPt = layout->data_pts;
1001 while (nextPt != NULL &&
1002 nextPt->y_pos != _CEFORMAT_ALL &&
1003 (data_pt->y_pos == _CEFORMAT_ALL || nextPt->y_pos < data_pt->y_pos))
1006 nextPt = nextPt->next_pt;
1009 data_pt->next_pt = nextPt;
1010 data_pt->x_units = 0;
1013 layout->data_pts = data_pt;
1015 lastPt->next_pt = data_pt;
1018 /******************************************************************************
1019 * Function: RemoveDataPoint
1022 *****************************************************************************/
1028 DataPoint *lastPt = NULL;
1029 DataPoint *curPt = layout->data_pts;
1031 while (curPt != NULL && curPt != data_pt)
1034 curPt = curPt->next_pt;
1039 data_pt->x_units = layout->info.cur_max_x - data_pt->left;
1041 layout->data_pts = curPt->next_pt;
1043 lastPt->next_pt = curPt->next_pt;
1047 /******************************************************************************
1048 * Function: GetCurrentDataPoint
1051 *****************************************************************************/
1053 GetCurrentDataPoint (
1059 data_pt->y_pos = _CEFORMAT_ALL;
1061 if (layout->data_pts != NULL)
1062 *data_pt = *(layout->data_pts);
1065 /******************************************************************************
1066 * Function: SetMargins
1068 * Purpose: Sets the margins.
1069 *****************************************************************************/
1074 layout->lmargin = 0;
1075 layout->rmargin = 0;
1076 layout->info.format_y = _CEFORMAT_ALL;
1078 if (layout->data_pts != NULL)
1083 layout->lmargin = layout->data_pts->left;
1084 layout->rmargin = layout->data_pts->right;
1086 layout->info.format_y = layout->data_pts->y_pos;
1089 layout->lmargin += layout->left;
1090 layout->rmargin += layout->right;
1093 /******************************************************************************
1094 * Function: SetTextPosition
1096 * Purpose: Sets the text beginning position to the left margin.
1097 * If 'first' is true, adds its value to the text beginning
1099 *****************************************************************************/
1105 layout->info.text_x_pos = layout->lmargin;
1107 layout->info.text_x_pos += layout->first;
1110 /******************************************************************************
1111 * Function: CheckFormat
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.
1117 * Calls SetMargins to set the correct margin
1118 * Calls SetTextPosition to set the text beginning position.
1119 *****************************************************************************/
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);
1131 SetTextPosition(layout, first);
1134 /******************************************************************************
1135 * Function: SaveLine
1137 * Initializes a line table element to the segment it should display.
1138 *****************************************************************************/
1141 _DtCanvasStruct *canvas,
1145 _DtCvUnit line_width,
1150 int i = canvas->line_cnt;
1154 if (i >= canvas->line_max)
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));
1162 canvas->line_lst = (_DtCvLineSeg *) malloc (
1163 (sizeof(_DtCvLineSeg) * canvas->line_max));
1165 * NOTE....should this routine return a value?
1166 * If (re)alloc error occurs, this simply ignores the problem.
1168 if (canvas->line_lst == NULL)
1170 canvas->line_max = 0;
1171 canvas->line_cnt = 0;
1177 * does this line exceed the current maximum?
1179 if (_DtCvLINE_HORZ == direction)
1190 if (layout->info.max_x_pos < x2)
1191 layout->info.max_x_pos = x2;
1193 if (layout->info.cur_max_x < x2)
1194 layout->info.cur_max_x = x2;
1197 * save the line information
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;
1210 /******************************************************************************
1211 * Function: SaveInfo
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 *****************************************************************************/
1219 _DtCanvasStruct *canvas,
1221 _DtCvSegmentI *new_seg,
1224 _DtCvSaveInfo (canvas, &(layout->info),
1225 layout->max_width, layout->rmargin, layout->txt_justify);
1227 while (layout->info.delayed_search_saves > 0) {
1228 _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
1229 layout->info.delayed_search_saves--;
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;
1240 CheckFormat(layout, FALSE);
1243 /******************************************************************************
1244 * Function: CheckSaveInfo
1246 * Purpose: Checks to see if there is any information to save and saves
1247 * it if there is any.
1248 *****************************************************************************/
1251 _DtCanvasStruct *canvas,
1253 _DtCvSegmentI *new_seg,
1256 if (layout->info.line_bytes)
1257 SaveInfo (canvas, layout, new_seg, start);
1260 /******************************************************************************
1261 * Function: ProcessStringSegment
1263 * chops a string segment up until its completely used.
1265 *****************************************************************************/
1267 ProcessStringSegment(
1268 _DtCanvasStruct *canvas,
1270 _DtCvSegmentI *cur_seg)
1272 layout->cur_start = 0;
1273 if (!(_DtCvIsSegSuperScript(cur_seg) || _DtCvIsSegSubScript(cur_seg))
1274 && (layout->super_script == True || layout->sub_script == True))
1276 layout->super_end = 0;
1277 layout->sub_end = 0;
1278 layout->super_script = False;
1279 layout->sub_script = False;
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);
1288 } /* End ProcessStringSegment */
1291 /******************************************************************************
1292 * Function: _DtCvUnit ResolveHeight(
1296 * Purpose: Determines the height of a row that is spanned.
1297 *****************************************************************************/
1301 CellInfo *cell_info,
1315 for (col = 0, cell = row * max_cols; col < max_cols; col++, cell++)
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.
1322 if (cell_info[cell].row_spn == -1 && cell_info[cell].col_spn != -1)
1325 * back up to the cell information containing the row
1334 } while (cell_info[topCell].row_spn == -1);
1337 * from here, start calculating the height of the row
1338 * spanning cell, and find out how big the row must
1341 i = cell_info[topCell].row_spn;
1344 while (i > 0 && zeroed > 0)
1346 total += row_info[topRow].height;
1347 if (row_info[topRow].height == 0)
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.
1363 * make sure we get a positive value out of
1364 * this for our height.
1366 if (cell_info[topCell].info.height > total)
1368 total = cell_info[topCell].info.height - total;
1369 total = total / span + (total % span ? 1 : 0);
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
1378 if (rowHeight < total)
1384 row_info[row].height = rowHeight;
1388 /******************************************************************************
1389 * Function: void AdjustHeight(
1393 * Purpose: Determines the height of rows that are spanned but the
1394 * the spanner needs more room than the calculated row height
1396 *****************************************************************************/
1399 CellInfo *cell_info,
1405 int cell = row * max_cols + col;
1408 _DtCvUnit adjustValue;
1411 if (cell_info[cell].col_spn == -1 || cell_info[cell].row_spn == -1)
1414 for (j = row, i = 0, total = 0; i < cell_info[cell].row_spn; i++, j++)
1415 total += row_specs[j].height;
1418 * adjust the row height to include all of the row spanning cell.
1420 if (total < cell_info[cell].info.height)
1422 _DtCvUnit totalUsed = 0;
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.
1429 adjustValue = cell_info[cell].info.height - total;
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.
1436 total = cell_info[cell].row_spn;
1438 for (i = 0; i < cell_info[cell].row_spn; i++)
1440 value = (((row_specs[row + i].height * 100) / total) * adjustValue)
1442 row_specs[row + i].height += value;
1447 * if didn't use all the size up - apply it evenly.
1449 if (totalUsed < adjustValue)
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--)
1455 value = adjustValue / j + (adjustValue % j ? 1 : 0);
1456 row_specs[row + i].height += value;
1457 adjustValue -= value;
1466 /******************************************************************************
1467 * Function: void ReFormatCell(
1470 * canvas Specifies the specific information about the
1472 * layout Specifies the currently active information
1473 * affecting the layout of information.
1475 * Purpose: Based on a height and width, relay out the information in a cell.
1476 *****************************************************************************/
1479 _DtCanvasStruct *canvas,
1481 CellInfo *this_cell,
1482 ColumnSpec *col_specs,
1484 _DtCvUnit new_height,
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;
1494 _DtCvValue junkValue;
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.
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;
1508 * determine the maximum width for the cell.
1510 for (i = this_cell->col_spn; i > 0; i--)
1511 cellWidth += col_specs[col++].actual;
1514 * get the current left and right margins.
1516 GetCurrentDataPoint(layout, &basePt);
1519 * re-format the cell
1521 FormatCell(canvas, layout, this_cell->cell_seg, cellWidth,
1523 basePt, &i, &cellWidth, &junk, &junkValue);
1526 * calculate the new height.
1528 this_cell->info.height = layout->info.y_pos - new_y;
1531 * if the new cell does not use the same number of lines as the
1532 * old formatting did, zero the length.
1534 while (canvas->txt_cnt < this_cell->info.cnt.end_txt)
1535 canvas->txt_lst[canvas->txt_cnt++].length = 0;
1538 * restore the saved counters
1540 canvas->txt_cnt = saveTxt;
1541 canvas->line_cnt = saveLn;
1542 layout->info.y_pos = saveYpos;
1543 layout->info.cur_max_x = saveMaxX;
1547 /******************************************************************************
1548 * Function: void FormatCell(
1551 * canvas Specifies the specific information about the
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.
1560 * Purpose: Determines the width and height of the cell. Also the begin/end
1561 * counts on text, graphics and lines.
1562 *****************************************************************************/
1565 _DtCanvasStruct *canvas,
1567 _DtCvSegmentI *cell_seg,
1568 _DtCvUnit span_width,
1569 _DtCvUnit min_height,
1572 _DtCvUnit *ret_width,
1573 _DtCvUnit *ret_height,
1574 _DtCvValue *ret_tab_flag)
1576 _DtCvStatus only1Col = True;
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;
1585 * set the limits/margins
1586 * assume the left_margin has been set by a previous call.
1588 layout->right = layout->max_width - base_pt.left - base_pt.right
1589 - layout->left - span_width;
1591 * set the minimum Y for the container.
1594 minY = saveYpos + min_height;
1597 * If a segment was specified for this cell, format it.
1599 if (cell_seg != NULL && &BlankTableCell != cell_seg)
1601 ProcessContainer(canvas, layout, cell_seg, minY,
1602 ret_width, &maxX, ret_ln);
1605 * check to see if the only thing in this container is a
1608 nextSeg = _DtCvContainerListOfSeg(cell_seg);
1609 *ret_tab_flag = True;
1610 while (True == *ret_tab_flag && NULL != nextSeg)
1613 * check to see if there is any segments that aren't one
1616 if (_DtCvIsSegTable(nextSeg) &&
1617 1 < _DtCvNumColsOfTableSeg(nextSeg))
1620 else if (!(_DtCvIsSegTable(nextSeg) || _DtCvIsSegNoop(nextSeg)))
1621 *ret_tab_flag = False;
1623 nextSeg = _DtCvNextSeg(nextSeg);
1626 if (True == *ret_tab_flag && True == only1Col)
1627 *ret_tab_flag = False;
1631 * Calculate the height and return it.
1633 *ret_height = layout->info.y_pos - saveYpos;
1636 * restore the right margin
1638 layout->right = saveRight;
1640 if (layout->info.cur_max_x < saveMaxX)
1641 layout->info.cur_max_x = saveMaxX;
1644 /******************************************************************************
1645 * Function: AdjustFrmtTxtOption
1647 *****************************************************************************/
1649 AdjustFrmtTxtOption(
1650 _DtCvSegmentI *p_seg,
1651 _DtCvFrmtOption option)
1653 if (p_seg != NULL && _DtCvIsSegContainer(p_seg))
1655 TxtHorizJustify(p_seg) = option;
1657 p_seg = _DtCvContainerListOfSeg(p_seg);
1658 while (p_seg != NULL)
1660 AdjustFrmtTxtOption(p_seg, option);
1661 p_seg = p_seg->next_seg;
1666 /******************************************************************************
1667 * Function: ResolveCell
1669 *****************************************************************************/
1672 _DtCanvasStruct *canvas,
1674 _DtCvSegmentI *table,
1675 ColumnSpec *col_specs,
1693 int cell = row * max_cols + col;
1694 _DtCvUnit cellWidth;
1696 _DtCvUnit retHeight;
1698 CellInfo *thisCell = &ret_info[cell];
1700 _DtCvValue reformat = False;
1701 _DtCvValue retTabFlag = False;
1702 _DtCvSegmentI **f_data = _DtCvCellsOfTableSeg(table);
1705 * if this column is spanned, skip
1707 if (thisCell->col_spn == -1 || thisCell->row_spn == -1)
1710 GetCurrentDataPoint(layout, &basePt);
1712 if (thisCell->cell_seg == NULL)
1714 idRefs = row_specs[row].next_id;
1717 * find the end of the id
1722 * set the starting info
1724 thisCell->col_spn = 1;
1725 thisCell->pos_x = basePt.left + layout->left;
1727 while (!done && col < max_cols)
1733 * move the ptr to the next id,
1734 * counting the characters in this id at the same time.
1737 while (NULL != ptr && *ptr != ' ' && *ptr != '\0')
1744 * set idRefs to the next id.
1747 while (NULL != idRefs && *idRefs == ' ')
1751 * Is this id and the next the same? If so,
1752 * it spans the columns
1754 if (0 != len && _DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
1755 (idRefs[len] == ' ' || idRefs[len] == '\0'))
1758 thisCell->col_spn++;
1759 ret_info[++cell].col_spn = -1;
1765 row_specs[row].next_id = idRefs;
1770 if (NULL != id && '\0' != *id)
1774 while (f_data != NULL && NULL != *f_data &&
1775 _DtCvStrCaseCmpLatin1(_DtCvContainerIdOfSeg(*f_data),id) != 0)
1778 * make sure to break the link to the next segment.
1779 * Otherwise, the formatting routines will format too much
1782 if (NULL != f_data && NULL != *f_data)
1784 _DtCvNextSeg(*f_data) = NULL;
1787 * assign the data to this cell.
1789 thisCell->cell_seg = *f_data;
1791 else /* there is no id for this cell, use a blank container */
1792 thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
1794 else /* there is no id for this cell, use a blank container */
1795 thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
1798 * how many rows does this cell span?
1804 for (done = False, count = 1, i = row + 1;
1805 0 < len && i < max_rows && False == done; i++)
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'))
1818 * invalidate the columns spanned in this row
1820 for (k = 0; k < thisCell->col_spn && k + myCol < max_cols; k++)
1822 ret_info[i * max_cols + myCol + k].col_spn = -1;
1823 ret_info[i * max_cols + myCol + k].row_spn = -1;
1826 idRefs = row_specs[i].next_id;
1830 * skip the current id.
1832 while (*idRefs != ' ' && *idRefs != '\0')
1836 * skip the space to the next id.
1838 while (*idRefs == ' ')
1842 * now test to see if this is a match
1843 * cycle if so. quit if the end of string
1846 } while (*idRefs != '\0' &&
1847 _DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
1848 (idRefs[len] == ' ' || idRefs[len] == '\0'));
1851 * the next non-spanned column in this row will use this id.
1853 row_specs[i].next_id = idRefs;
1857 if (NULL != id && '\0' != *id)
1860 thisCell->row_spn = count;
1863 for (i = 0, cellWidth = 0; i < thisCell->col_spn; i++)
1864 cellWidth += col_specs[myCol + i].actual;
1867 * set the start line and text information
1869 SetBeginCounts(canvas, &(thisCell->info.cnt));
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!
1876 if (&BlankTableCell != thisCell->cell_seg)
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;
1887 FormatCell(canvas, layout, thisCell->cell_seg, cellWidth,
1888 row_specs[row].height, basePt,
1889 &brdCnt, &retWidth, &retHeight, &retTabFlag);
1891 if (&BlankTableCell != thisCell->cell_seg)
1892 _DtCvContainerTMarginOfSeg(thisCell->cell_seg) = saveTop;
1895 * set some ending information
1897 thisCell->info.height = retHeight;
1898 thisCell->info.width = retWidth;
1899 SetEndCounts(canvas, &(thisCell->info.cnt), brdCnt);
1902 * check the height against previous heights
1904 if (row_specs[row].height < retHeight && thisCell->row_spn == 1)
1905 row_specs[row].height = retHeight;
1908 * check for run over of the desired widths
1910 if (retWidth > cellWidth)
1917 _DtCvUnit slopUsed = 0;
1918 _DtCvUnit slop = retWidth - cellWidth; /* the amount of room
1919 required of the neighbors */
1922 * set the reformat flag
1924 if (False == retTabFlag)
1928 * determine the maximum size the column can occupy
1930 for (j = 0, cellMax = 0;
1931 j < thisCell->col_spn && j + myCol < max_cols; j++)
1932 cellMax += col_specs[myCol+j].max;
1935 * determine the maximum available space from the neighbors.
1937 for (j = myCol + thisCell->col_spn, maxSlop = 0; j < max_cols; j++)
1938 maxSlop = maxSlop + col_specs[j].actual - col_specs[j].min;
1941 * If the slop demanded is larger than available,
1942 * simply reduced the other column specifications to their smallest
1945 if (slop >= maxSlop)
1947 for (j = myCol + thisCell->col_spn; j < max_cols; j++)
1948 col_specs[j].actual = col_specs[j].min;
1951 * Is it allowed for this column to 'hang over' the others?
1953 * And is it the first one? I.e. don't allow more than one
1954 * cell per row to overhang it's neighbors.
1956 * And only allow it if the vertical text justification places
1957 * the text at the top of the cell.
1959 if (_DtCvTRUE == col_specs[myCol].hanger
1960 && 0 == row_specs[row].y_adj
1961 && _DtCvJUSTIFY_TOP == TxtVertJustify(thisCell->cell_seg))
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.
1971 row_specs[row].y_adj = retHeight -
1972 _DtCvContainerBMarginOfSeg(thisCell->cell_seg);
1973 row_specs[row].column = myCol;
1977 * clear the reformat flag
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.
1990 for (j = myCol + thisCell->col_spn; j < max_cols; j++)
1992 percent = col_specs[j].actual - col_specs[j].min;
1993 value = slop * percent / maxSlop;
1995 col_specs[j].actual -= value;
1999 * if any more slop is needed, grab it on a strictly
2004 for (j = myCol + thisCell->col_spn, slopUsed = 0;
2005 slop > slopUsed && j < max_cols; j++)
2007 if (col_specs[j].actual > col_specs[j].min)
2009 col_specs[j].actual--;
2013 } while (slopUsed > 0 && slop > slopUsed);
2017 * set the column width in the controlling column struct.
2019 if (thisCell->col_spn == 1)
2021 col_specs[myCol].actual = retWidth;
2026 * how much to spread among the columns?
2028 slop = cellMax - retWidth;
2031 * if the aggragate max width is smaller than required,
2032 * allocate the excess among the columns.
2037 * set the desired to the max and calculate the leftover
2038 * slop and the maximum desired size.
2040 for (j = 0, slop = retWidth, maxSlop = 0;
2041 myCol + j < max_cols && j < thisCell->col_spn; j++)
2043 col_specs[j].actual = col_specs[myCol + j].max;
2044 slop -= col_specs[myCol + j].max;
2045 maxSlop += col_specs[myCol + j].max;
2048 * now allocate the leftover slop to each colum
2049 * based on the maximum desired size.
2051 for (j = 0, slopUsed = 0;
2052 slop > slopUsed && myCol + j < max_cols
2053 && j < thisCell->col_spn; j++)
2055 value = slop * col_specs[myCol + j].max / maxSlop;
2056 if (((slop*col_specs[myCol+j].max) % maxSlop) >= (maxSlop/2))
2058 col_specs[myCol + j].actual += value;
2066 j < max_cols && j < myCol + thisCell->col_spn; j++)
2068 percent = col_specs[j].max - col_specs[j].actual;
2069 value = slop * percent / maxSlop;
2071 col_specs[j].actual += value;
2076 for (j = myCol, slopUsed = 0; slop > slopUsed &&
2077 j < max_cols && j < myCol + thisCell->col_spn; j++)
2079 if (col_specs[j].actual < col_specs[j].max)
2081 col_specs[j].actual++;
2085 } while (slopUsed > 0 && slop > slopUsed);
2087 else /* if (slop == 0) */
2089 for (j = 0; myCol + j < max_cols && j < thisCell->col_spn; j++)
2090 col_specs[j].actual = col_specs[myCol + j].max;
2098 /******************************************************************************
2099 * Function: ProcessTable
2101 *****************************************************************************/
2104 _DtCanvasStruct *canvas,
2106 _DtCvSegmentI *table,
2119 int saveLnStart = canvas->line_cnt;
2120 int saveTxtStart = canvas->txt_cnt;
2121 int saveTravCnt = canvas->trav_cnt;
2122 _DtCvUnit workWidth;
2124 _DtCvUnit saveLeft = layout->left;
2125 _DtCvUnit saveYpos = layout->info.y_pos;
2126 _DtCvUnit tableYpos;
2127 _DtCvUnit newHeight;
2129 _DtCvUnit oldAlignPos;
2130 short anchorRow = -1;
2132 const char **widthStr;
2133 const char *saveAlignChar = layout->info.align_char;
2135 char *alignCharacters = NULL;
2138 _DtCvFrmtOption saveTxtJustify = layout->txt_justify;
2139 _DtCvFrmtOption colJustify = _DtCvJUSTIFY_LEFT;
2140 _DtCvFrmtOption *colJustSpec;
2142 _DtCvValue oldFound = layout->id_found;
2143 _DtCvValue haveBrds = False;
2144 _DtCvValue saveState = layout->table_flag;
2145 _DtCvValue saveAlignFlag = layout->info.align_flag;
2146 _DtCvValue saveAlignPos = layout->info.align_pos;
2150 CellInfo *cellInfo = &defCell;
2151 ColumnSpec defColumn;
2152 ColumnSpec *colSpecs = &defColumn;
2154 RowSpec *rowSpecs = &defRow;
2156 GrpInfo grpInfo = DefGrpInfo;
2159 * get the base margins that the table will be working in.
2161 GetCurrentDataPoint(layout, &basePt);
2164 * find out how many rows there are.
2166 for (rowIds = _DtCvCellIdsOfTableSeg(table), maxRows = 0;
2167 rowIds != NULL && rowIds[maxRows] != NULL; maxRows++);
2173 * get the number of columns and the column widths
2175 maxCols = _DtCvNumColsOfTableSeg(table);
2176 widthStr = (const char **)_DtCvColWOfTableSeg(table);
2177 colJustSpec = _DtCvColJustifyOfTableSeg(table);
2182 if (widthStr == NULL)
2183 widthStr = DefWidth;
2186 * determine the width the table has to work with.
2188 workWidth = layout->max_width - basePt.left - basePt.right -
2189 layout->left - layout->right;
2194 * turn the string specifying column widths into units.
2198 colSpecs = (ColumnSpec *) malloc (sizeof(ColumnSpec) * maxCols);
2199 if (colSpecs == NULL)
2204 rowSpecs = (RowSpec *) malloc (sizeof(RowSpec) * maxRows);
2205 if (rowSpecs == NULL)
2212 if (maxRows != 1 || maxCols != 1)
2214 cellInfo = (CellInfo *) malloc (sizeof(CellInfo) * maxCols * maxRows);
2215 if (cellInfo == NULL)
2226 * for each column, process the width specification.
2227 * '+Optimal,Take,Give'
2229 * + - means the cell can 'hang over' its neighbors.
2230 * It will take everything it can get and then
2231 * push the other below it. (Labeled lists).
2232 * Optimal - The desired percentage of the available space to
2233 * use for the column.
2234 * Take - The percentage amount the column will take from
2235 * other columns to make itself 'fit'.
2236 * Give - The percentage amount the column is willing to give up
2237 * to other columns for them to 'fit'.
2239 for (col = 0, divisor = 0; col < maxCols; col++)
2241 const char *nxtWidth = *widthStr;
2244 * move to the meat of the width specification string.
2246 SkipToNumber(&nxtWidth);
2249 * set the correct 'allow hangers' flag.
2251 colSpecs[col].hanger = _DtCvFALSE;
2252 if ('+' == *nxtWidth)
2254 colSpecs[col].hanger = _DtCvTRUE;
2259 * now process the O,G,T specification.
2261 a = GetValueFromString(&nxtWidth, 1); if (a < 1) a = 1;
2262 b = GetValueFromString(&nxtWidth, 0); if (b < 0) b = 0;
2263 c = GetValueFromString(&nxtWidth, b); if (c > a) c = a;
2266 * for now just get the base percentages.
2268 colSpecs[col].min = a - c;
2269 colSpecs[col].actual = a;
2270 colSpecs[col].max = a + b;
2273 * get the column justification.
2275 if (NULL != colJustSpec)
2277 colJustify = *colJustSpec;
2280 colSpecs[col].justify = colJustify;
2281 if (_DtCvINHERIT == colJustify)
2282 colSpecs[col].justify = saveTxtJustify;
2285 * up the divisor value.
2287 divisor += colSpecs[col].actual;
2290 * skip to the next set of width specifications
2292 if (col + 1 < maxCols && NULL != widthStr[1])
2296 * initialize the cell information for the rows in this column
2298 for (row = 0; row < maxRows; row++)
2300 cellInfo[row * maxCols + col].cell_seg = NULL;
2301 cellInfo[row * maxCols + col].col_spn = 0;
2302 cellInfo[row * maxCols + col].row_spn = 0;
2303 cellInfo[row * maxCols + col].info = DefLayFrmtInfo;
2308 * initialize the row specs
2311 if (-1 != min_y && 1 == maxRows)
2312 newHeight = min_y - saveYpos;
2313 for (row = 0; row < maxRows; row++)
2315 rowSpecs[row].column = -1;
2316 rowSpecs[row].y_adj = 0;
2317 rowSpecs[row].height = newHeight;
2318 rowSpecs[row].height = newHeight;
2319 rowSpecs[row].next_id = rowIds[row];
2323 * now figure the real values
2327 for (col = 0; col < maxCols; col++)
2329 colSpecs[col].min = workWidth * colSpecs[col].min / divisor;
2330 colSpecs[col].actual = workWidth * colSpecs[col].actual / divisor;
2331 colSpecs[col].max = workWidth * colSpecs[col].max / divisor;
2333 if (colSpecs[col].min < 1)
2334 colSpecs[col].min = 1;
2335 if (colSpecs[col].actual < 1)
2336 colSpecs[col].actual = 1;
2337 if (colSpecs[col].max < 1)
2338 colSpecs[col].max = 1;
2342 * now process the table.
2344 tableYpos = layout->info.y_pos;
2346 alignCharacters = _DtCvJustifyCharsOfTableSeg(table);
2349 * set up the state of table processing and
2350 * the beginning line/text counts.
2352 layout->table_flag = True;
2353 SetBeginCounts(canvas, &(grpInfo.cnt));
2356 * now process each column, row by row.
2357 * Doing it row by row allows the columns to shake out their
2358 * sizing with less reformatting.
2360 for (col = 0; col < maxCols; col++)
2363 * remember where this column starts.
2365 saveTravCnt = canvas->trav_cnt;
2366 saveLnStart = canvas->line_cnt;
2367 saveTxtStart = canvas->txt_cnt;
2368 newLeft = layout->left;
2369 colJustify = layout->txt_justify;
2370 layout->txt_justify = colSpecs[col].justify;
2373 * initialize the JUSTIFY_NUM or JUSTIFY_CHAR information
2375 layout->info.align_pos = 0;
2376 layout->info.align_char = PeriodStr;
2377 if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
2380 * are any alignment characters specified?
2382 if (NULL != alignCharacters && '\0' != alignCharacters)
2384 int len = mblen(alignCharacters, MB_CUR_MAX);
2387 * copy the character into a buffer
2389 strncpy(alignBuf, alignCharacters, len);
2390 alignBuf[len] = '\0';
2391 layout->info.align_char = alignBuf;
2394 * are there more characters? If so increment for the
2395 * next column that may have JUSTIFY_CHAR. Otherwise,
2396 * leave alone and re-use for other columns.
2398 if ('\0' != alignCharacters[len])
2399 alignCharacters += len;
2402 /* no...then default */
2404 layout->txt_justify = _DtCvJUSTIFY_LEFT;
2409 * reset the counts to the start
2411 canvas->trav_cnt = saveTravCnt;
2412 canvas->line_cnt = saveLnStart;
2413 canvas->txt_cnt = saveTxtStart;
2414 layout->left = newLeft;
2417 * for each row, format the cell in this columns
2419 for (row = 0, redo = False, cell = col;
2420 row < maxRows && redo == False;
2421 row++, cell += maxCols)
2424 * remember the old height
2426 rowSpecs[row].lst_height = rowSpecs[row].height;
2429 * set the alignment flag for each column in the row.
2431 layout->info.align_flag = False;
2432 if (_DtCvJUSTIFY_CHAR == layout->txt_justify ||
2433 _DtCvJUSTIFY_NUM == layout->txt_justify)
2434 layout->info.align_flag = True;
2437 * remember the alignment position
2439 oldAlignPos = layout->info.align_pos;
2442 * layout all the cells jammed to the top of the table.
2443 * later, they get moved down to their position.
2445 layout->info.y_pos = tableYpos;
2446 redo = ResolveCell(canvas, layout, table,
2447 colSpecs, rowSpecs, col, row,
2448 maxCols, maxRows, cellInfo);
2450 * check for maximum row span
2452 if (maxRowSpn < cellInfo[cell].row_spn)
2453 maxRowSpn = cellInfo[cell].row_spn;
2456 * did the cell have borders?
2458 if (0 != cellInfo[cell].info.cnt.my_lines)
2462 * check to see if the specified anchor has been found in
2463 * this row. If so, save some information for later use.
2465 if (anchorRow == -1 && oldFound != layout->id_found)
2469 * check to see if the alignment position has changed.
2470 * for all but the first row!
2472 if (0 != row && oldAlignPos != layout->info.align_pos)
2478 for (a = 0; a < row; a++)
2481 * restore the old row heights for this column
2483 rowSpecs[a].height = rowSpecs[a].lst_height;
2486 * reset the hanging cell information.
2488 if (col == rowSpecs[a].column)
2490 rowSpecs[a].column = -1;
2491 rowSpecs[a].y_adj = 0;
2496 } while (redo == True);
2499 * push the next column to the right by size of this column
2501 layout->left += colSpecs[col].actual;
2504 * restore the horizontal text justification
2506 layout->txt_justify = colJustify;
2510 * set the ending counts for the lines/text in the table.
2511 * and save the information as long as we are not a table
2512 * that is a descendant of some container with a border and
2513 * our cells include borders and we're going to have to honor
2516 SetEndCounts(canvas, &(grpInfo.cnt), 0);
2517 if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint &&
2518 False == layout->brdr_flag && True == haveBrds)
2520 GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
2523 * warning - nothing done if malloc error.
2528 * initialize to the line counts for the table
2533 * set the linked list information
2535 info->next_info = layout->grp_lst;
2536 layout->grp_lst = info;
2541 * Now go back and search for zeroed row heights and fill them in
2542 * based on spanned rows. This can only happen if maxRowSpn is
2543 * greater than 1! Otherwise, a row height really did end up zero!
2548 * try to resolve the zero height rows
2550 for (a = 1, redo = True; redo && a < maxRowSpn; a++)
2553 for (row = 0; row < maxRows; row++)
2555 if (rowSpecs[row].height == 0 &&
2556 ResolveHeight(rowSpecs, cellInfo, maxCols, row, a) == 0)
2562 * if any of the rows comes up unresolved, force to an average
2565 * But only do this if the first cell *does not* span all the rows
2569 cellInfo[0].row_spn != maxRows && cellInfo[0].col_spn != maxCols)
2571 for (row = 0; row < maxRows; row++)
2573 if (rowSpecs[row].height == 0)
2574 rowSpecs[row].height = canvas->metrics.line_height;
2579 * Now, double check that the row heights will accomodate
2582 for (row = 0; row < maxRows; row++)
2583 for (col = 0; col < maxCols; col++)
2584 AdjustHeight(cellInfo, rowSpecs, maxCols, row, col);
2588 * now check that the minimum heights used for the rows matches
2589 * or exceeds the minimum y position required.
2595 for (newHeight = 0, row = 0; row < maxRows; row++)
2596 newHeight += rowSpecs[row].height;
2598 if (tableYpos + newHeight < min_y)
2600 newHeight = tableYpos - min_y;
2601 for (row = 0; 0 < newHeight && row < maxRows; row++)
2603 pad = (newHeight/(maxRows-row));
2604 rowSpecs[row].height += pad;
2611 * now reposition the cells based on the final row heights.
2613 layout->info.y_pos = tableYpos;
2614 for (tableYpos = 0, cell = 0, row = 0; row < maxRows;
2615 tableYpos = tableYpos + rowSpecs[row].height + rowSpecs[row].y_adj,
2619 * check to see if the specified anchor has been found in this
2620 * row. If so, adjust the found position.
2622 if (anchorRow == row)
2623 layout->id_Ypos += tableYpos;
2625 for (col = 0, layout->left = saveLeft; col < maxCols;
2626 layout->left += colSpecs[col++].actual, cell++)
2628 if (cellInfo[cell].cell_seg != NULL)
2631 * calculate the new height
2633 for (newHeight = 0, a = 0; a < cellInfo[cell].row_spn; a++)
2635 newHeight += rowSpecs[row + a].height;
2636 if (col != rowSpecs[row + a].column)
2637 newHeight += rowSpecs[row + a].y_adj;
2641 * calculate the new width.
2643 for (newWidth = 0, a = 0; a < cellInfo[cell].col_spn; a++)
2644 newWidth += colSpecs[col + a].actual;
2647 * now get the overhang space for this cell
2650 if (col > rowSpecs[row].column)
2651 workWidth = rowSpecs[row].y_adj;
2654 * if the heights (and/or width for spanning columns)
2655 * are different, check to see if the
2656 * cell contains lines that may be affected by the
2657 * height adjustment.
2659 * It is strongly assumed that if a table specifies that
2660 * a cell can hang over it's neighbors that it will *NOT*
2661 * have borders (whereby LinesMayChange is false) and
2662 * newWidth will not be greater than the cell's width.
2664 if ((newHeight > cellInfo[cell].info.height &&
2665 True == LinesMayChange(canvas,
2666 cellInfo[cell].info.cnt.beg_ln,
2667 cellInfo[cell].info.cnt.end_ln,
2668 cellInfo[cell].info.cnt.my_lines))
2670 (1 < cellInfo[cell].col_spn &&
2671 newWidth > cellInfo[cell].info.width))
2672 ReFormatCell(canvas, layout, &cellInfo[cell], colSpecs,
2674 layout->info.y_pos + tableYpos);
2677 /* adjust the cell rather than reformatting */
2678 AdjustObjectPosition(canvas, layout,
2679 TxtVertJustify(cellInfo[cell].cell_seg),
2680 cellInfo[cell].info.cnt.beg_txt ,
2681 cellInfo[cell].info.cnt.beg_ln ,
2682 cellInfo[cell].info.cnt.beg_brk ,
2683 cellInfo[cell].info.cnt.end_txt ,
2684 cellInfo[cell].info.cnt.end_ln ,
2685 cellInfo[cell].info.cnt.end_brk ,
2686 cellInfo[cell].info.cnt.my_lines,
2687 newHeight - cellInfo[cell].info.height,
2689 tableYpos, workWidth);
2695 * increment the maximum y.
2697 layout->info.y_pos += tableYpos;
2698 layout->left = saveLeft;
2704 if (maxRows > 1 || maxCols > 1)
2707 layout->txt_justify = saveTxtJustify;
2708 layout->table_flag = saveState;
2711 * restore the alignment information
2713 layout->info.align_flag = saveAlignFlag;
2714 layout->info.align_char = saveAlignChar;
2715 layout->info.align_pos = saveAlignPos;
2718 /******************************************************************************
2719 * Function: UpdateDimensionArrays
2721 * Purpose: Based on the object's orientation and justification,
2722 * update the correct dimension array(s).
2724 *****************************************************************************/
2726 UpdateDimensionArrays(
2727 _DtCvSegmentI *p_seg,
2734 _DtCvUnit *max_left,
2735 _DtCvUnit *max_right)
2740 _DtCvFrmtOption orient = ObjHorizOrient(p_seg);
2741 _DtCvFrmtOption vOrient = ObjVertOrient(p_seg);
2744 * modify the width that headSize should be
2750 case _DtCvJUSTIFY_RIGHT_MARGIN:
2752 case _DtCvJUSTIFY_CENTER:
2754 case _DtCvJUSTIFY_LEFT_MARGIN:
2755 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2758 if ((*top_bot)[i][j][DIMS_WIDTH] < width)
2759 (*top_bot)[i][j][DIMS_WIDTH] = width;
2761 if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(p_seg))
2762 (*top_bot)[i][j][DIMS_HEIGHT] += height;
2768 * check left & right margins.
2770 marginPtr = max_left;
2776 case _DtCvJUSTIFY_RIGHT_CORNER:
2777 case _DtCvJUSTIFY_RIGHT:
2779 marginPtr = max_right;
2781 case _DtCvJUSTIFY_LEFT_CORNER:
2782 case _DtCvJUSTIFY_LEFT:
2783 if (vOrient != _DtCvJUSTIFY_TOP)
2785 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2789 * push i to zero or 4
2791 if (orient == _DtCvJUSTIFY_RIGHT_CORNER ||
2792 orient == _DtCvJUSTIFY_LEFT_CORNER)
2795 (*corner)[i][j] += height;
2796 if (*marginPtr < width)
2799 else if (_DtCvContainerFlowOfSeg(p_seg) != _DtCvWRAP)
2801 (*side)[i][j] += height;
2802 if (*marginPtr < width)
2807 (*flow)[j][DIMS_HEIGHT] += height;
2808 if ((*flow)[j][DIMS_WIDTH] < width)
2809 (*flow)[j][DIMS_WIDTH] = width;
2815 /******************************************************************************
2816 * Function: DetermineMaxDims
2818 *****************************************************************************/
2823 _DtCvUnit left_margin,
2824 _DtCvUnit right_margin,
2825 _DtCvUnit *top_height,
2826 _DtCvUnit *bot_height,
2827 _DtCvUnit *max_width)
2834 * now process all the information gathered about the (sub)headings
2835 * to determine the bounding box for the (head) txt. Start by figuring
2836 * out the maximums for the dimensions.
2838 * figure the current top and bottom max widths.
2840 topWidth = left_margin + right_margin;
2841 botWidth = left_margin + right_margin;
2844 for (j = DIMS_LM; j <= DIMS_RM; j++)
2846 topWidth = topWidth + (*top_bot)[DIMS_TOP] [j][DIMS_WIDTH];
2847 botWidth = botWidth + (*top_bot)[DIMS_BOTTOM][j][DIMS_WIDTH];
2849 if (*top_height < (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT])
2850 *top_height = (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT];
2852 if (*bot_height < (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT])
2853 *bot_height = (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT];
2857 * for the maximum top and bottom heights, take into
2858 * consideration the corner values
2860 if (*top_height < (*corner)[DIMS_TC][DIMS_LEFT])
2861 *top_height = (*corner)[DIMS_TC][DIMS_LEFT];
2862 if (*top_height < (*corner)[DIMS_TC][DIMS_RIGHT])
2863 *top_height = (*corner)[DIMS_TC][DIMS_RIGHT];
2865 if (*bot_height < (*corner)[DIMS_BC][DIMS_LEFT])
2866 *bot_height = (*corner)[DIMS_BC][DIMS_LEFT];
2867 if (*bot_height < (*corner)[DIMS_BC][DIMS_RIGHT])
2868 *bot_height = (*corner)[DIMS_BC][DIMS_RIGHT];
2870 *max_width = topWidth;
2871 if (*max_width < botWidth)
2872 *max_width = botWidth;
2876 /******************************************************************************
2877 * Function: DetermineFlowConstraints
2879 *****************************************************************************/
2881 DetermineFlowConstraints(
2884 _DtCvUnit left_margin,
2885 _DtCvUnit right_margin,
2888 DataPoint *right_pt)
2890 _DtCvUnit leftSide = flow_dims[DIMS_LEFT][DIMS_HEIGHT];
2891 _DtCvUnit rightSide = flow_dims[DIMS_RIGHT][DIMS_HEIGHT];
2894 * Now, if there is flowing text required, put points on the
2895 * stack to indicate them.
2897 left_margin += flow_dims[DIMS_LEFT][DIMS_WIDTH];
2898 right_margin += flow_dims[DIMS_RIGHT][DIMS_WIDTH];
2900 GetCurrentDataPoint(layout, left_pt);
2901 GetCurrentDataPoint(layout, right_pt);
2902 left_pt->left += left_margin;
2903 left_pt->right += right_margin;
2904 left_pt->y_pos = _CEFORMAT_ALL;
2905 right_pt->left += left_margin;
2906 right_pt->right += right_margin;
2907 right_pt->y_pos = _CEFORMAT_ALL;
2909 while (leftSide > 0 || rightSide > 0)
2913 if (rightSide == 0 || leftSide <= rightSide)
2915 left_pt->right = right_margin;
2916 left_pt->y_pos = start_y + leftSide;
2917 if (leftSide != rightSide)
2920 InsertDataPoint(layout, left_pt);
2926 if (leftSide == 0 || leftSide > rightSide)
2928 right_pt->left = left_margin;
2929 right_pt->y_pos = start_y + rightSide;
2930 if (leftSide != rightSide)
2933 InsertDataPoint(layout, right_pt);
2939 /******************************************************************************
2940 * Function: DetermineHeadPositioning
2942 *****************************************************************************/
2944 DetermineHeadPositioning(
2951 _DtCvUnit block_size,
2952 _DtCvUnit *ret_side_size)
2955 _DtCvUnit leftSideHeight = 0;
2956 _DtCvUnit rightSideHeight = 0;
2957 _DtCvUnit sideHeight = 0;
2960 * determine the maximum side heights
2962 for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
2964 leftSideHeight += (*side)[i][DIMS_LEFT];
2965 rightSideHeight += (*side)[i][DIMS_RIGHT];
2969 * determine the maximum side height
2971 sideHeight = block_size;
2972 if (sideHeight < leftSideHeight)
2973 sideHeight = leftSideHeight;
2974 if (sideHeight < rightSideHeight)
2975 sideHeight = rightSideHeight;
2976 if (sideHeight < (*flow)[DIMS_LEFT][DIMS_HEIGHT])
2977 sideHeight = (*flow)[DIMS_LEFT][DIMS_HEIGHT];
2978 if (sideHeight < (*flow)[DIMS_RIGHT][DIMS_HEIGHT])
2979 sideHeight = (*flow)[DIMS_RIGHT][DIMS_HEIGHT];
2982 * calculate the starting Y position for each of the positions
2983 * reuse the arrays that were used to save the max dimension values.
2985 for (i = DIMS_LM; i <= DIMS_RM; i++)
2987 (*top_bot)[DIMS_TOP] [i][DIMS_YPOS] = start_y;
2988 (*top_bot)[DIMS_BOTTOM][i][DIMS_YPOS] = start_y + max_top + sideHeight;
2991 (*corner)[DIMS_TC][DIMS_LEFT] = start_y;
2992 (*corner)[DIMS_TC][DIMS_RIGHT] = start_y;
2994 (*corner)[DIMS_BC][DIMS_LEFT] = start_y + max_top + sideHeight;
2995 (*corner)[DIMS_BC][DIMS_RIGHT] = start_y + max_top + sideHeight;
2997 (*side)[DIMS_TOP][DIMS_LEFT] = start_y + max_top;
2998 (*side)[DIMS_TOP][DIMS_RIGHT] = start_y + max_top;
3000 (*flow)[DIMS_LEFT ][DIMS_YPOS] = start_y + max_top;
3001 (*flow)[DIMS_RIGHT][DIMS_YPOS] = start_y + max_top;
3003 (*side)[DIMS_CENTER][DIMS_LEFT] = start_y + max_top +
3004 (sideHeight - (*side)[DIMS_CENTER][DIMS_LEFT]) / 2;
3005 (*side)[DIMS_CENTER][DIMS_RIGHT] = start_y + max_top +
3006 (sideHeight - (*side)[DIMS_CENTER][DIMS_RIGHT]) / 2;
3008 (*side)[DIMS_BOTTOM][DIMS_LEFT] = start_y + max_top +
3009 sideHeight - (*side)[DIMS_BOTTOM][DIMS_LEFT];
3010 (*side)[DIMS_BOTTOM][DIMS_RIGHT] = start_y + max_top +
3011 sideHeight - (*side)[DIMS_BOTTOM][DIMS_RIGHT];
3013 if (ret_side_size != NULL)
3014 *ret_side_size = sideHeight;
3017 /******************************************************************************
3018 * Function: AdjustHead
3021 * base_left Specifies the x position that the controller
3022 * occupying 'left_margin' space would start
3024 * block_width Specifies the body's width for which to
3025 * center or align a controller with.
3026 * left_margin Specifies the space used by a controller
3027 * that is on the left side of the body.
3028 * right_margin Specifies the space used by a controller
3029 * on the right side of the body.
3031 *****************************************************************************/
3034 _DtCanvasStruct *canvas,
3036 _DtCvSegmentI *p_seg,
3043 _DtCvUnit base_left,
3044 _DtCvUnit block_width,
3045 _DtCvUnit left_margin,
3046 _DtCvUnit right_margin)
3048 int i = DIMS_TOP; /* also DIMS_TC */
3049 int j = DIMS_LEFT; /* also DIMS_LM */
3051 _DtCvUnit adjustX = 0;
3052 _DtCvUnit adjustY = 0;
3054 _DtCvUnit headWidth = info->width;
3055 _DtCvFrmtOption orient = ObjHorizOrient(p_seg);
3056 _DtCvFrmtOption vOrient = ObjVertOrient(p_seg);
3058 if (_DtCvContainerPercentOfSeg(p_seg) == 10000
3059 && orient == _DtCvJUSTIFY_CENTER
3060 && TxtHorizJustify(p_seg) == _DtCvJUSTIFY_LEFT)
3061 headWidth = block_width;
3065 case _DtCvJUSTIFY_RIGHT_MARGIN:
3068 case _DtCvJUSTIFY_CENTER:
3069 adjustX = (block_width - headWidth) / divisor;
3071 case _DtCvJUSTIFY_LEFT_MARGIN:
3072 adjustX += left_margin;
3073 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3076 newY = (*top_bot)[i][j][DIMS_YPOS];
3077 (*top_bot)[i][j][DIMS_YPOS] += info->height;
3080 case _DtCvJUSTIFY_RIGHT_CORNER:
3081 adjustX = block_width + left_margin;
3084 case _DtCvJUSTIFY_LEFT_CORNER:
3085 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3088 newY = (*corner)[i][j];
3089 (*corner)[i][j] += info->height;
3092 case _DtCvJUSTIFY_RIGHT:
3093 adjustX = block_width + left_margin;
3096 case _DtCvJUSTIFY_LEFT:
3097 if (vOrient != _DtCvJUSTIFY_TOP)
3099 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3102 if (_DtCvContainerFlowOfSeg(p_seg) == _DtCvWRAP)
3104 if (orient == _DtCvJUSTIFY_LEFT)
3105 adjustX += left_margin;
3107 adjustX -= headWidth;
3109 newY = (*flow)[j][DIMS_YPOS];
3110 (*flow)[j][DIMS_YPOS] += info->height;
3114 newY = (*side)[i][j];
3115 (*side)[i][j] += info->height;
3120 adjustY = newY - base_y;
3121 adjustX += base_left;
3124 * adjust the text positions
3126 AdjustTextPositions(canvas, info->cnt.beg_txt, info->cnt.end_txt,
3130 * adjust the lines positions
3132 AdjustLinePositions(canvas, info->cnt.beg_ln, info->cnt.end_ln,
3136 * adjust the page breaks, but only if necessary.
3138 AdjustPgBrk(canvas, info->cnt.beg_brk, info->cnt.end_brk, adjustY);
3141 /******************************************************************************
3142 * Function: InitDimArrays
3144 *****************************************************************************/
3155 for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
3157 for (j = DIMS_LM; j <= DIMS_RM; j++)
3159 (*top_bot)[i][j][DIMS_WIDTH] = 0;
3160 (*top_bot)[i][j][DIMS_HEIGHT] = 0;
3162 for (j = DIMS_LEFT; j <= DIMS_RIGHT; j++)
3165 for (i = DIMS_LEFT; i <= DIMS_RIGHT; i++)
3167 for (j = DIMS_WIDTH; j <= DIMS_HEIGHT; j++)
3169 (*corner)[i][j] = 0;
3175 /******************************************************************************
3176 * Function: ProcessController
3177 *****************************************************************************/
3178 static LayFrmtInfo *
3180 _DtCanvasStruct *canvas,
3182 _DtCvSegmentI *cur_seg)
3185 int saveTravCnt = canvas->trav_cnt;
3186 _DtCvUnit saveYPos = layout->info.y_pos;
3187 _DtCvUnit saveMaxWidth = layout->max_width;
3188 _DtCvUnit saveLeft = layout->left;
3189 _DtCvUnit saveRight = layout->right;
3192 _DtCvUnit myMaxWidth;
3193 LayFrmtInfo *frmtInfo;
3199 * Controllers always break the formatting sequence.
3200 * So save any information in the buffer, reset the margins and
3201 * add the appropriate lines, and check for going over boundaries.
3203 CheckSaveInfo(canvas, layout, cur_seg, 0);
3204 CheckFormat(layout, True);
3207 * Get the controller specific information.
3208 * disallow some of the orientation & vOrient combinations
3210 if ((ObjHorizOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3211 && ObjVertOrient(cur_seg) != _DtCvJUSTIFY_BOTTOM)
3213 (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3214 && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3215 && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT))
3216 ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
3218 if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP
3220 (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3222 (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_TOP
3223 && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3224 && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT)))
3225 _DtCvContainerFlowOfSeg(cur_seg) = _DtCvWRAP_NONE;
3227 if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP_JOIN
3229 (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3230 || ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT_MARGIN))
3232 ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
3233 ObjHorizOrient(cur_seg) = _DtCvJUSTIFY_LEFT_MARGIN;
3237 * malloc a formatting dimension structure and initialize it with
3238 * default values. This will be returned to the caller.
3240 frmtInfo = (LayFrmtInfo *) malloc (sizeof(LayFrmtInfo));
3241 *frmtInfo = DefLayFrmtInfo;
3244 * the controller object begins here.
3246 SetBeginCounts(canvas, &(frmtInfo->cnt));
3249 * set the parent's data point in the stack
3251 GetCurrentDataPoint(layout, &basePt);
3254 * calculate the amount of space the controller can occupy.
3255 * first calculate the amount of space to work with.
3256 * then truncate to zero if necessary.
3257 * then use the percentage of that remaining area as the space
3258 * the controller's segments can occupy.
3260 myMaxWidth = layout->max_width - basePt.left - basePt.right
3261 - saveLeft - saveRight;
3265 myMaxWidth = (_DtCvUnit) (((double) myMaxWidth)
3266 * ((double) _DtCvContainerPercentOfSeg(cur_seg))
3271 * Format the controller at a 'zero'ed point.
3272 * The lines it generates will be moved later to their correct position.
3277 PushDataPoint(layout, &zeroPt);
3280 * now process as a regular container
3284 * set some counts and flags (necessary for a redo).
3287 canvas->trav_cnt = saveTravCnt;
3288 canvas->line_cnt = frmtInfo->cnt.beg_ln;
3289 canvas->txt_cnt = frmtInfo->cnt.beg_txt;
3290 layout->max_width = myMaxWidth;
3291 layout->info.y_pos = 0;
3294 * process the container
3296 ProcessContainer(canvas,layout,cur_seg,-1,&maxWidth,&maxXPos,&getLn);
3299 * check to see if we need to reformat because the minimum size
3300 * is larger than we asked for.
3302 if (maxXPos + _DtCvContainerRMarginOfSeg(cur_seg) > myMaxWidth)
3305 myMaxWidth = maxXPos + _DtCvContainerRMarginOfSeg(cur_seg);
3307 } while (True == redo);
3310 * remove this element's data points from the stack.
3312 RemoveDataPoint(layout, &zeroPt);
3315 * set the ending counts for the items in this container.
3317 SetEndCounts(canvas, &(frmtInfo->cnt), getLn);
3318 frmtInfo->width = myMaxWidth;
3319 frmtInfo->height = layout->info.y_pos;
3322 * does this controller want to join with the lines in a non-controller?
3324 if (_DtCvWRAP_JOIN == _DtCvContainerFlowOfSeg(cur_seg)
3325 && frmtInfo->cnt.beg_txt != canvas->txt_cnt)
3326 _DtCvSetJoinInfo(&(layout->info), True, canvas->txt_cnt - 1);
3329 * Restore the previous information
3331 if (NULL != layout->lst_rendered)
3332 layout->lst_rendered->next_disp = NULL;
3334 layout->left = saveLeft;
3335 layout->right = saveRight;
3336 layout->max_width = saveMaxWidth;
3337 layout->lst_rendered = NULL;
3338 layout->info.y_pos = saveYPos;
3343 /******************************************************************************
3344 * Function: AdjustForBorders
3346 * Initializes the display line and graphic tables.
3347 *****************************************************************************/
3350 _DtCanvasStruct *canvas,
3352 _DtCvFrmtOption brdr,
3353 _DtCvUnit line_width,
3355 _DtCvUnit *ret_right)
3358 * if the line_width is zero, make it 1 so that is really takes
3361 if (0 == line_width)
3365 * set the flag for processing a border
3367 if (_DtCvBORDER_NONE != brdr)
3368 layout->brdr_flag = True;
3371 * check to see if this element has a border. If so, adjust the
3374 if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3375 || brdr == _DtCvBORDER_TOP
3376 || brdr == _DtCvBORDER_TOP_LEFT
3377 || brdr == _DtCvBORDER_TOP_RIGHT)
3378 layout->info.y_pos += line_width;
3381 if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3382 || brdr == _DtCvBORDER_BOTTOM
3383 || brdr == _DtCvBORDER_BOTTOM_LEFT
3384 || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3385 *ret_bot = line_width;
3387 if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3388 || brdr == _DtCvBORDER_LEFT
3389 || brdr == _DtCvBORDER_TOP_LEFT
3390 || brdr == _DtCvBORDER_BOTTOM_LEFT)
3391 layout->left += line_width;
3394 if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3395 || brdr == _DtCvBORDER_RIGHT
3396 || brdr == _DtCvBORDER_TOP_RIGHT
3397 || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3399 layout->right += line_width;
3400 *ret_right = line_width;
3404 /******************************************************************************
3405 * Function: DrawBorders
3408 * canvas Specifies the virtual canvas on which
3410 * layout Specifies the current layout information.
3411 * brdr Specifies the type of border.
3412 * top_y Specifes the top y of the bounding box for
3413 * the object. Any border drawn should be
3414 * completely below this y.
3415 * bot_y Specifes the bottom y of the bounding box
3416 * for the object. Any border drawn should be
3417 * completely below this y.
3418 * left_x Specifies the left x of the bounding box
3419 * for the object. Any border drawn should be
3420 * completely to the right of this x.
3421 * right_x Specifies the right x of the bounding box
3422 * for the object. Any border drawn should be
3423 * completely to the left of this x.
3428 * top_y ---> xxxxxxxxxxxxxxxxxxxxxx
3429 * xxxxxxxxxxxxxxxxxxxxxx
3430 * xx------------------xx
3431 * xx| |xx (xx represents the line.)
3435 * xx------------------xx
3436 * bot_y ---> xxxxxxxxxxxxxxxxxxxxxx
3437 * xxxxxxxxxxxxxxxxxxxxxx
3439 *****************************************************************************/
3442 _DtCanvasStruct *canvas,
3444 _DtCvFrmtOption brdr,
3446 _DtCvUnit line_width,
3453 int cnt = canvas->line_cnt;
3457 * if line_width is zero, make it 1 so that it really takes
3460 if (0 == line_width)
3464 * calculate the width of the element.
3466 width = right_x - left_x;
3469 * If borders are specified, draw them
3471 if (brdr != _DtCvBORDER_NONE)
3474 * now do the horizontal borders. the coordinates are the top,
3475 * left most unit of the line.
3479 case _DtCvBORDER_FULL:
3480 case _DtCvBORDER_HORZ:
3481 case _DtCvBORDER_BOTTOM:
3482 case _DtCvBORDER_BOTTOM_LEFT:
3483 case _DtCvBORDER_BOTTOM_RIGHT:
3484 SaveLine(canvas, layout, _DtCvLINE_HORZ,
3486 left_x, bot_y, width);
3488 if (brdr == _DtCvBORDER_BOTTOM
3489 || brdr == _DtCvBORDER_BOTTOM_LEFT
3490 || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3493 case _DtCvBORDER_TOP:
3494 case _DtCvBORDER_TOP_LEFT:
3495 case _DtCvBORDER_TOP_RIGHT:
3496 SaveLine(canvas, layout, _DtCvLINE_HORZ,
3498 left_x, top_y, width);
3502 * for vertical lines, the coordinates are the top, right most
3507 case _DtCvBORDER_FULL:
3508 case _DtCvBORDER_BOTTOM_LEFT:
3510 * include the line width in length for a full
3513 bot_y += line_width;
3515 case _DtCvBORDER_VERT:
3516 case _DtCvBORDER_LEFT:
3517 case _DtCvBORDER_TOP_LEFT:
3518 SaveLine(canvas, layout, _DtCvLINE_VERT,
3520 left_x, top_y, bot_y - top_y);
3521 if (brdr == _DtCvBORDER_LEFT
3522 || brdr == _DtCvBORDER_TOP_LEFT
3523 || brdr == _DtCvBORDER_BOTTOM_LEFT)
3526 case _DtCvBORDER_BOTTOM_RIGHT:
3528 * if we didn't fall thru from above, we need to
3529 * add the extension to the bottom to get the
3530 * full length for the right vertical line.
3532 if (brdr == _DtCvBORDER_BOTTOM_RIGHT)
3533 bot_y += line_width;
3535 case _DtCvBORDER_RIGHT:
3536 case _DtCvBORDER_TOP_RIGHT:
3537 SaveLine(canvas, layout, _DtCvLINE_VERT,
3539 right_x - line_width, top_y, bot_y - top_y);
3543 return ((canvas->line_cnt - cnt) * mod);
3546 /******************************************************************************
3547 * Function: AdjustObjectPosition
3550 * canvas Specifies the virtual canvas on which
3552 * justify Specifies the vertical adjustment for the
3554 * start_txt Specifies the start index of the text list.
3555 * start_gr Specifies the start index of the graphics list.
3556 * start_ln Specifies the start index of the line list.
3557 * end_txt Specifies the end indext of the text list.
3558 * end_gr Specifies the end indext of the graphics list.
3559 * end_ln Specifies the end indext of the line list.
3560 * height_adj Specifies the internal height adjust value.
3561 * Depending on the justify type, this may
3562 * add to y_adj for text and regions, bottom
3563 * lines and the height of vertical lines.
3564 * y_adj Specifies the y position adjustment.
3565 * Lines, text and regions are moved this
3567 * internal_y Specifies the internal y position adjustment.
3568 * height_adj includes this value. Text and
3569 * regions are moved this amount.
3573 *****************************************************************************/
3575 AdjustObjectPosition(
3576 _DtCanvasStruct *canvas,
3578 _DtCvFrmtOption justify,
3586 _DtCvUnit height_adj,
3589 _DtCvUnit internal_y)
3595 * If border count is negative, indicates the first line in the
3596 * list is bottom line. This requires special handling in adjusting
3597 * its position. Set flags accordingly.
3602 brdr_cnt = -brdr_cnt;
3606 * calculate the offset value within the object for other objects
3607 * contained in this object.
3609 if (justify != _DtCvJUSTIFY_TOP)
3611 yOff = height_adj - internal_y;
3612 if (justify == _DtCvJUSTIFY_CENTER)
3620 * don't modify the border lines around this object yet.
3625 * modify the border lines of the objects contained within
3628 AdjustLinePositions(canvas, start_ln, end_ln, x_adj, yOff);
3631 * now adjust the border lines around this object.
3635 AdjustLinePositions(canvas, start_ln, end_ln, x_adj, y_adj);
3638 * now fix the lines if they've changed height and move
3639 * the first line to its bottom position if necessary.
3641 if (0 != height_adj)
3643 while (start_ln < end_ln)
3646 * indicates the bottom line is the first line in the
3647 * list. Move it down the height adjustment.
3651 canvas->line_lst[start_ln].pos_y += height_adj;
3652 canvas->line_lst[start_ln].max_y += height_adj;
3657 * stretch the vertical lines
3659 else if (canvas->line_lst[start_ln].dir == _DtCvLINE_VERT)
3660 canvas->line_lst[start_ln].max_y += height_adj;
3667 * adjust the position of the text within this object.
3669 AdjustTextPositions (canvas, start_txt, end_txt, x_adj, yOff);
3672 * adjust the position of the text within this object.
3674 AdjustPgBrk (canvas, start_brk, end_brk, yOff);
3677 /******************************************************************************
3678 * Function: LinesMayChange
3681 * canvas Specifies the virtual canvas on which
3683 * start_ln Specifies the start index of the line list.
3684 * end_ln Specifies the end indext of the line list.
3686 * Return: True if there is a vertical line as a child of a container.
3687 * False if there are no vertical lines in the child of a
3690 *****************************************************************************/
3693 _DtCanvasStruct *canvas,
3699 * If border count is negative, indicates that one of the lines
3700 * is for the bottom of the container/cell. Ignore for now.
3701 * we want to check the lines in the container/cell.
3704 brdr_cnt = -brdr_cnt;
3707 * get rid of the line count for this object,
3708 * AdjustObjectPosition can take care of it.
3713 * Now check for vertical lines that would
3714 * be affected by a height change.
3716 while (start_ln < end_ln)
3718 if (_DtCvLINE_VERT == canvas->line_lst[start_ln].dir)
3726 /******************************************************************************
3727 * Function: ProcessContainer
3729 * Initializes the display line and graphic tables.
3730 *****************************************************************************/
3733 _DtCanvasStruct *canvas,
3735 _DtCvSegmentI *con_seg,
3737 _DtCvUnit *ret_width,
3738 _DtCvUnit *ret_max_x,
3742 const char *saveJustifyChar = layout->info.align_char;
3745 _DtCvUnit maxWidth = 0;
3746 _DtCvUnit maxXPos = 0;
3747 _DtCvUnit myMinY = -1;
3748 _DtCvUnit saveLeft = layout->left;
3749 _DtCvUnit saveRight = layout->right;
3750 _DtCvUnit saveLead = layout->info.leading;
3751 _DtCvUnit saveFirst = layout->first;
3752 _DtCvUnit saveYpos = layout->info.y_pos;
3753 _DtCvValue saveStatic = layout->stat_flag;
3754 _DtCvValue saveBrdr = layout->brdr_flag;
3755 _DtCvFrmtOption saveJustify = layout->txt_justify;
3756 LayFrmtInfo frmtInfo;
3761 * check to see if this element breaks the formatting sequence.
3762 * If so save any information in the buffer, reset the margins and
3763 * add the appropriate lines, and check for going over boundaries.
3765 if (NotJoining(layout))
3767 CheckSaveInfo(canvas, layout, con_seg, 0);
3768 CheckFormat(layout, True);
3772 * check to see if this segment is the segment we want as our first
3775 CheckId(layout, _DtCvContainerIdOfSeg(con_seg));
3778 * Set beginning text and line counts
3780 frmtInfo = DefLayFrmtInfo;
3781 SetBeginCounts(canvas, &(frmtInfo.cnt));
3784 * Get the first indent and set the current container pointer to me.
3786 layout->first = _DtCvContainerFMarginOfSeg(con_seg) / layout->divisor;
3787 layout->left = _DtCvContainerLMarginOfSeg(con_seg) / layout->divisor;
3788 layout->right = _DtCvContainerRMarginOfSeg(con_seg) / layout->divisor;
3789 layout->info.leading = _DtCvContainerLeadingOfSeg(con_seg);
3792 * check to see if we violate the horiz_pad_hint on the left, right or
3795 if (canvas->metrics.horiz_pad_hint > _DtCvContainerLMarginOfSeg(con_seg))
3796 layout->left = _DtCvContainerLMarginOfSeg(con_seg);
3797 else if (layout->left < canvas->metrics.horiz_pad_hint)
3798 layout->left = canvas->metrics.horiz_pad_hint;
3800 if (canvas->metrics.horiz_pad_hint > _DtCvContainerRMarginOfSeg(con_seg))
3801 layout->right = _DtCvContainerRMarginOfSeg(con_seg);
3802 else if (layout->right < canvas->metrics.horiz_pad_hint)
3803 layout->right = canvas->metrics.horiz_pad_hint;
3805 if (canvas->metrics.horiz_pad_hint > _DtCvContainerFMarginOfSeg(con_seg))
3806 layout->first = _DtCvContainerFMarginOfSeg(con_seg);
3807 else if (layout->first < canvas->metrics.horiz_pad_hint)
3808 layout->first = canvas->metrics.horiz_pad_hint;
3811 * check to see if there is more squeeze room available.
3813 if (layout->left > canvas->metrics.horiz_pad_hint
3814 || layout->right > canvas->metrics.horiz_pad_hint
3815 || layout->first > canvas->metrics.horiz_pad_hint)
3816 layout->margin_non_zero = True;
3819 * set the formatting type for this container
3821 layout->stat_flag = False;
3822 if (_DtCvContainerTypeOfSeg(con_seg) == _DtCvLITERAL)
3823 layout->stat_flag = True;
3826 * check to see if this element breaks the formatting sequence.
3827 * If so, add lines, etc.
3829 if (NotJoining(layout))
3832 * Adjust margins and y position for bordering
3834 AdjustForBorders (canvas, layout, Border(con_seg), BrdWidth(con_seg),
3837 _DtCvAddSpace(_DtCvContainerTMarginOfSeg(con_seg),
3838 &(layout->info.y_pos));
3840 * check for flow limits.
3842 CheckFormat(layout, True);
3845 * get the parent's data point in the stack
3846 * and add the current container's left and right to it.
3848 GetCurrentDataPoint(layout, &basePt);
3849 basePt.left += saveLeft;
3850 basePt.right += saveRight;
3853 * if we don't inherit the the text justification
3854 * set the new value.
3856 if (_DtCvINHERIT != _DtCvContainerJustifyOfSeg(con_seg))
3858 layout->txt_justify = _DtCvContainerJustifyOfSeg(con_seg);
3859 if (_DtCvJUSTIFY_NUM == layout->txt_justify)
3860 layout->info.align_char = PeriodStr;
3861 else if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
3863 layout->info.align_char = _DtCvContainerJustifyCharOfSeg(con_seg);
3865 * check to see if the character is 'valid'.
3866 * if not, default out of JUSTIFY_CHAR
3868 if (NULL != layout->info.align_char ||
3869 '\0' == layout->info.align_char)
3870 layout->txt_justify = _DtCvJUSTIFY_LEFT;
3875 * terminate the previous rendering list
3877 if (NULL != layout->lst_rendered)
3878 layout->lst_rendered->next_disp = NULL;
3879 layout->lst_rendered = NULL;
3882 * push the data point and reset margin/text info.
3884 PushDataPoint(layout, &basePt);
3886 SetTextPosition(layout, True);
3890 * determine the minimum Y that the child of this container should
3891 * occupy. To do so, subtract off the bottom border pad and the
3896 myMinY = min_y - yPad;
3897 if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3901 _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg), &bPad);
3907 * format the segment
3909 saveYpos = layout->info.y_pos;
3911 GetCurrentDataPoint(layout, &curPt);
3914 * reset the max x variable
3916 layout->info.cur_max_x = 0;
3917 ProcessSegmentList(canvas, layout, _DtCvContainerListOfSeg(con_seg),
3919 &maxWidth, &maxXPos, NULL);
3921 * if this container forces a wrap join of the next item,
3922 * save the current line, but don't add space or null the
3923 * last rendered item.
3925 CheckSaveInfo(canvas, layout, con_seg, 0);
3926 if (maxWidth < layout->info.cur_max_x - curPt.left + layout->right)
3927 maxWidth = layout->info.cur_max_x - curPt.left + layout->right;
3928 if (maxXPos < layout->info.cur_max_x)
3929 maxXPos = layout->info.cur_max_x;
3931 if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3934 * Save any information in the buffer,
3935 * reset the margins and add the appropriate lines,
3936 * and check for going over boundaries.
3938 _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg),
3939 &(layout->info.y_pos));
3942 * terminate the previous rendering list
3944 if (NULL != layout->lst_rendered)
3945 layout->lst_rendered->next_disp = NULL;
3946 layout->lst_rendered = NULL;
3950 * remove this element's data points from the stack.
3952 RemoveDataPoint(layout, &basePt);
3955 * include the bottom border (if needed) in the ending y position
3957 layout->info.y_pos += yPad;
3960 * Set the ending counts for the lines and text in me.
3961 * This sets the ending counts for the lines contained in me,
3962 * NOT the lines in my border.
3964 SetEndCounts(canvas, &(frmtInfo.cnt), 0);
3967 * does this object need to be adjust within its height?
3969 if (0 < min_y && layout->info.y_pos < min_y)
3971 AdjustObjectPosition(canvas, layout, TxtVertJustify(con_seg),
3972 frmtInfo.cnt.beg_txt, frmtInfo.cnt.beg_ln,
3973 frmtInfo.cnt.beg_brk,
3974 frmtInfo.cnt.end_txt, frmtInfo.cnt.end_ln,
3975 frmtInfo.cnt.end_brk,
3976 0, min_y - layout->info.y_pos - yPad, 0, 0, 0);
3977 layout->info.y_pos = min_y;
3981 * Now draw the borders
3982 * If borders are drawn, cur_max_x & max_x_pos may get changed
3983 * if a right side border is drawn.
3985 if (maxWidth < layout->max_width - curPt.left - curPt.right)
3986 maxWidth = layout->max_width - curPt.left - curPt.right;
3988 getLn = DrawBorders (canvas, layout, Border(con_seg),
3989 BrdData(con_seg), BrdWidth(con_seg),
3990 saveYpos, layout->info.y_pos - yPad,
3992 curPt.left + maxWidth);
3995 * check to see if we need to save the container counts away
3996 * because we might need to move the entire container as one
3997 * to honor the boundary. This will occur if the flag to honor
3998 * a boundary is set to _DtCvUSE_BOUNDARY_MOVE, this container has
3999 * border lines, the container's parent is not a table nor
4000 * is the container within another container that has a border.
4002 if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint
4003 && True == layout->brdr_flag
4004 && False == saveBrdr && False == layout->table_flag)
4006 GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
4009 * warning - nothing done if malloc error.
4014 * initialize to the end information of the container.
4016 info->cnt = frmtInfo.cnt;
4019 * take into account the borders for this container
4021 SetEndCounts(canvas, &(info->cnt), getLn);
4024 * set the linked list information
4026 info->next_info = layout->grp_lst;
4027 layout->grp_lst = info;
4032 * set the return values.
4034 *ret_max_x = layout->info.cur_max_x;
4035 *ret_width = maxWidth;
4036 if (*ret_width < layout->max_width - curPt.left - curPt.right)
4037 *ret_width = layout->max_width - curPt.left - curPt.right;
4040 * Restore the previous information
4042 layout->left = saveLeft;
4043 layout->right = saveRight;
4044 layout->first = saveFirst;
4045 layout->stat_flag = saveStatic;
4046 layout->brdr_flag = saveBrdr;
4047 layout->info.leading = saveLead;
4050 * Besides checking for flow constraints, also (re)sets margins and
4053 CheckFormat(layout, True);
4054 layout->txt_justify = saveJustify;
4055 layout->info.align_char = saveJustifyChar;
4058 * for tables and such, return how many lines were drawn around this
4067 /******************************************************************************
4068 * Function: ProcessSegmentList
4070 * Process the segment list, laying it out according to left, right,
4071 * and first margins specified. Returns the max_width of the all
4072 * segments processed and the maximum x coordinate used.
4073 *****************************************************************************/
4076 _DtCanvasStruct *canvas,
4078 _DtCvSegmentI *cur_seg,
4080 _DtCvUnit *ret_width,
4081 _DtCvUnit *ret_max_x,
4085 int saveTravCnt = canvas->trav_cnt;
4086 int saveTxtCnt = canvas->txt_cnt;
4087 int saveLineCnt = canvas->line_cnt;
4088 int saveBrkCnt = canvas->brk_cnt;
4092 _DtCvUnit nWidth = 0;
4093 _DtCvUnit leftMargin = 0;
4094 _DtCvUnit rightMargin = 0;
4095 _DtCvUnit topHeight = 0;
4096 _DtCvUnit botHeight = 0;
4097 _DtCvUnit maxWidth = 0;
4098 _DtCvUnit saveYpos = layout->info.y_pos;
4099 _DtCvSegmentI *segStart = cur_seg;
4100 LayFrmtInfo *headInfo = NULL;
4101 LayFrmtInfo *lastHead = NULL;
4102 LayFrmtInfo *nxtHead;
4103 _DtCvLayoutInfo startInfo;
4105 _DtCvValue redo = False;
4106 _DtCvValue joinCleared = False;
4111 CornerDims cornerDims;
4118 * clear the controller arrays
4120 InitDimArrays(&topBot, &sideDims, &cornerDims, &flowDims);
4123 * get the current left and right values or 'base'.
4125 GetCurrentDataPoint(layout, &basePt);
4132 leftPt.y_pos = _CEFORMAT_ALL;
4133 rightPt.y_pos = _CEFORMAT_ALL;
4136 * process all the controller type containers in the segment list
4138 while (NULL != cur_seg)
4140 if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4143 * want to clear this once and only once. Then any join
4144 * directives will survive, though if two or more controllers
4145 * have the directive set, the 'last' one will win out.
4147 if (False == joinCleared)
4149 _DtCvSetJoinInfo(&(layout->info), False, -1);
4154 * process the 'controller'
4156 nxtHead = ProcessController(canvas, layout, cur_seg);
4159 * update the dimension arrays so that the controller
4160 * will get placed correctly.
4162 UpdateDimensionArrays(cur_seg, nxtHead->width, nxtHead->height,
4163 &topBot, &sideDims, &cornerDims, &flowDims,
4164 &leftMargin, &rightMargin);
4167 * remember this controller.
4169 if (NULL == headInfo)
4172 lastHead->next_info = nxtHead;
4177 * go to the next segment
4179 cur_seg = cur_seg->next_seg;
4183 * Now reset the margins based on the controllers found
4185 if (NULL != headInfo)
4187 DetermineMaxDims(&topBot, &cornerDims, leftMargin, rightMargin,
4188 &topHeight, &botHeight, &maxWidth);
4189 layout->info.y_pos += topHeight;
4190 layout->left += leftMargin;
4191 layout->right += rightMargin;
4192 DetermineFlowConstraints(layout, flowDims,
4193 basePt.left, basePt.right,
4194 layout->info.y_pos, &leftPt, &rightPt);
4197 * get rid of the leftMargin and rightMargin values in maxWidth
4198 * otherwise the use of layout->left & layout->right will double
4201 maxWidth = maxWidth - leftMargin - rightMargin;
4202 if (layout->max_width < maxWidth + basePt.left + basePt.right +
4203 layout->left + layout->right)
4204 layout->max_width = maxWidth + basePt.left + basePt.right +
4205 layout->left + layout->right;
4208 SetTextPosition(layout, True);
4209 if (JoinSet(layout))
4212 int joinLine = layout->info.join_line;
4213 int start = canvas->txt_lst[joinLine].byte_index;
4214 int count = canvas->txt_lst[joinLine].length;
4215 _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4219 * change the starting location of the following text.
4220 * take into account the left margin that *hasn't*
4221 * been added to the controlling container.
4223 layout->info.text_x_pos = canvas->txt_lst[joinLine].text_x
4225 layout->info.cur_len = 0;
4228 * now calculate the width of this line.
4230 while (pSeg != NULL && count > 0)
4232 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4233 &cnt, &tmpWidth, NULL);
4234 layout->info.text_x_pos += tmpWidth;
4237 pSeg = pSeg->next_disp;
4243 * now format for non-controller containers and non-containers.
4244 * re-start at the beginning.
4249 * Save some information incase we have to redo the layout. I.e.
4250 * we overflow the sizing.
4252 startInfo = layout->info;
4253 saveTravCnt = canvas->trav_cnt;
4254 saveTxtCnt = canvas->txt_cnt;
4255 saveLineCnt = canvas->line_cnt;
4256 saveBrkCnt = canvas->brk_cnt;
4258 while (NULL != cur_seg)
4260 width = layout->max_width - layout->info.text_x_pos
4261 - layout->rmargin - layout->info.cur_len;
4264 * check to see if this item should start a line.
4266 CheckSetLineStart(layout, cur_seg);
4269 * check to see if this item will cause a page break.
4271 CheckForPageBreak(canvas, cur_seg, layout->info.y_pos);
4273 switch (_DtCvPrimaryTypeOfSeg(cur_seg))
4275 case _DtCvCONTAINER:
4276 if (!(_DtCvIsSegController(cur_seg)))
4277 ProcessContainer(canvas, layout, cur_seg, min_y,
4278 &junk, &junk, &junk);
4283 * flag that this segment needs a line number
4285 cur_seg->internal_use = (void *) -1;
4288 * process the segment
4290 if (_DtCvIsSegInLine(cur_seg))
4293 * if a hypertext link, this will add it to
4294 * the internal list.
4296 CheckAddToHyperList(canvas, cur_seg);
4299 * get the traversal width
4301 nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4302 layout->info.lst_hyper);
4305 * check to see if this region can end a line
4307 flag = _DtCvCheckLineSyntax(canvas,cur_seg,0,0,False);
4310 * if this can't end a line, get the length up to
4311 * the next segment that can and base whether to
4312 * save pased on that.
4317 tempLen = _DtCvGetNextWidth(canvas,
4319 layout->info.lst_hyper,
4321 0, cur_seg, NULL, NULL, NULL);
4323 * if the next width is zero, reset the flag.
4331 * if not joining, but my length goes over the
4332 * working width, save out the current buffered
4335 if (NotJoining(layout) &&
4336 _DtCvWidthOfRegionSeg(cur_seg) + tempLen > width)
4337 CheckSaveInfo (canvas, layout, cur_seg, 0);
4340 * up counts on the buffered information.
4342 layout->info.line_bytes += 1;
4343 layout->info.cur_len +=
4344 (_DtCvWidthOfRegionSeg(cur_seg) + nWidth);
4347 * does the next segment need to join with
4348 * this one? If so, set the information
4350 _DtCvSetJoinInfo(&(layout->info), (flag ? 0 : 1), -1);
4351 if (_DtCvIsSegNewLine(cur_seg))
4352 SaveInfo(canvas, layout, cur_seg, 0);
4357 * clear out the join information
4358 * standalone figures can't join with others.
4360 _DtCvSetJoinInfo(&(layout->info), False, -1);
4363 * figures are standalone. Save any
4364 * information in the buffer away.
4366 CheckSaveInfo (canvas, layout, cur_seg, 0);
4369 * check to see if this segment is
4370 * a hypertext. If so, add it to the
4371 * list if it hasn't been added yet.
4373 CheckAddToHyperList(canvas, cur_seg);
4376 * get the traversal width, if any.
4378 nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4379 layout->info.lst_hyper);
4382 * now save the standalone figure
4384 layout->info.line_bytes += 1;
4385 layout->info.cur_len +=
4386 _DtCvWidthOfRegionSeg(cur_seg) + nWidth;
4387 SaveInfo(canvas, layout, cur_seg->next_seg, 0);
4390 * check for wrapping overflow
4392 CheckFormat(layout, False);
4396 * indicate this segment as the last item rendered
4398 if (NULL != layout->lst_rendered)
4399 layout->lst_rendered->next_disp = cur_seg;
4400 layout->lst_rendered = cur_seg;
4405 * lines are standalone. Save any
4406 * information in the buffer away.
4408 CheckSaveInfo (canvas, layout, cur_seg, 0);
4411 * if the line_width is zero, make it 1 so
4412 * that it really does take some space.
4414 nWidth = _DtCvWidthOfLineSeg(cur_seg);
4419 * start with it going all the way across the window.
4421 width = layout->max_width;
4425 * or does it only extend across the container?
4427 if (_DtCvIsSegBlockLine(cur_seg))
4429 tempX = layout->lmargin;
4430 width = layout->max_width - tempX - layout->rmargin;
4433 SaveLine (canvas, layout, _DtCvLINE_HORZ,
4434 _DtCvDataOfLineSeg(cur_seg), nWidth, tempX,
4435 layout->info.y_pos, width);
4437 layout->info.y_pos += nWidth;
4442 * check to see if marker is the target id
4444 CheckId(layout, _DtCvIdOfMarkerSeg(cur_seg));
4448 if (_DtCvIsSegNewLine(cur_seg))
4449 SaveInfo(canvas, layout, cur_seg, 0);
4454 * flag that this segment needs a line number
4456 cur_seg->internal_use = (void *) -1;
4459 * process the string
4461 ProcessStringSegment(canvas, layout, cur_seg);
4464 * check for wrapping overflow.
4466 if (_DtCvIsSegNewLine(cur_seg))
4467 CheckFormat(layout, False);
4470 * indicate this segment as the last item rendered
4472 if (NULL != layout->lst_rendered)
4473 layout->lst_rendered->next_disp = cur_seg;
4474 layout->lst_rendered = cur_seg;
4478 ProcessTable(canvas, layout, cur_seg, min_y);
4484 * get the next segment
4486 cur_seg = cur_seg->next_seg;
4489 * check the flowing text points
4491 if (leftPt.y_pos > 0 &&
4492 leftPt.x_units > layout->max_width - leftPt.left - leftPt.right)
4494 layout->max_width = leftPt.x_units + leftPt.left + leftPt.right;
4497 if (rightPt.y_pos > 0 &&
4498 rightPt.x_units > layout->max_width-rightPt.left-rightPt.right)
4500 layout->max_width = rightPt.x_units + rightPt.left + rightPt.right;
4505 * have we violated the available space?
4506 * if so, we'll have to reformat.
4512 canvas->trav_cnt = saveTravCnt;
4513 canvas->txt_cnt = saveTxtCnt;
4514 canvas->line_cnt = saveLineCnt;
4515 canvas->brk_cnt = saveBrkCnt;
4516 layout->info = startInfo;
4518 if (rightPt.y_pos > 0)
4520 RemoveDataPoint(layout, &rightPt); /* make sure its gone */
4521 InsertDataPoint(layout, &rightPt);
4523 if (leftPt.y_pos > 0)
4525 RemoveDataPoint(layout, &leftPt); /* make sure its gone */
4526 InsertDataPoint(layout, &leftPt);
4530 * Now reset the margins based on the controllers found
4532 if (NULL != headInfo)
4534 layout->left += leftMargin;
4535 layout->right += rightMargin;
4537 SetTextPosition(layout, True);
4538 if (JoinSet(layout))
4541 int joinLine = layout->info.join_line;
4542 int start = canvas->txt_lst[joinLine].byte_index;
4543 int count = canvas->txt_lst[joinLine].length;
4544 _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4548 * change the starting location of the following text.
4549 * take into account the left margin that *hasn't*
4550 * been added to the controlling container.
4552 layout->info.text_x_pos = canvas->txt_lst[joinLine].text_x
4554 layout->info.cur_len = 0;
4557 * now calculate the width of this line.
4559 while (pSeg != NULL && count > 0)
4561 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4562 &cnt, &tmpWidth, NULL);
4563 layout->info.text_x_pos += tmpWidth;
4566 pSeg = pSeg->next_disp;
4573 RemoveDataPoint(layout, &leftPt);
4574 RemoveDataPoint(layout, &rightPt);
4577 * if there were heads, now place them correctly.
4579 if (NULL != headInfo)
4581 _DtCvUnit blockHeight;
4582 _DtCvUnit blockWidth;
4585 * make sure all of the information in the body is saved out
4587 CheckSaveInfo (canvas, layout, NULL, 0);
4590 * now calculate the non-controllers overall height.
4592 blockHeight = layout->info.y_pos - saveYpos - topHeight;
4595 * now figure the head positions.
4597 DetermineHeadPositioning(&topBot, &sideDims, &cornerDims, &flowDims,
4598 saveYpos, topHeight,
4599 blockHeight, &blockHeight);
4601 * if the maximum available space was exceeded by the text
4602 * calculate a new max width
4604 if (layout->max_width < layout->info.cur_max_x + layout->right)
4605 layout->max_width = layout->info.cur_max_x + layout->right;
4607 blockWidth = layout->max_width - basePt.left - basePt.right
4608 - layout->left - layout->right;
4612 while (cur_seg != NULL)
4614 if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4616 AdjustHeadPosition(canvas, layout, cur_seg,
4617 &topBot, &sideDims, &cornerDims, &flowDims, nxtHead,
4618 0, basePt.left + layout->left - leftMargin, blockWidth,
4619 leftMargin, rightMargin);
4621 * go to the next head element
4623 nxtHead = nxtHead->next_info;
4626 * free the information.
4633 * got to the next segment
4635 cur_seg = cur_seg->next_seg;
4638 if (layout->info.y_pos < saveYpos + topHeight + blockHeight)
4639 layout->info.y_pos = saveYpos + topHeight + blockHeight;
4641 layout->info.y_pos += botHeight;
4645 * set the return values
4647 *ret_width = layout->info.cur_max_x - basePt.left + layout->right;
4648 *ret_max_x = layout->info.cur_max_x;
4653 /*****************************************************************************
4654 * Function: static _DtCvUnit MaxOfGroup (
4656 * Purpose: Determine the maximum of a group.
4657 *****************************************************************************/
4662 _DtCvLineSeg *lines,
4671 group->min_x = max_x;
4673 group->top_y = max_y;
4677 * find the maximum of the group
4679 for (i = group->cnt.beg_txt; i < group->cnt.end_txt; i++)
4682 * check for min's and max's
4684 if (group->min_x > text[i].text_x)
4685 group->min_x = text[i].text_x;
4687 if (group->max_x < text[i].max_x)
4688 group->max_x = text[i].max_x;
4690 if (group->top_y > text[i].baseline - text[i].ascent)
4691 group->top_y = text[i].baseline - text[i].ascent;
4693 if (group->bot_y < text[i].baseline + text[i].descent)
4694 group->bot_y = text[i].baseline + text[i].descent;
4697 * indicate that this line has been processed already
4699 _DtCvSetProcessed(text[i]);
4702 for (i = group->cnt.beg_ln; i < group->cnt.end_ln; i++)
4705 * check for min's and max's
4707 if (group->min_x > lines[i].pos_x)
4708 group->min_x = lines[i].pos_x;
4710 if (group->max_x < lines[i].max_x)
4711 group->max_x = lines[i].max_x;
4713 if (group->top_y > lines[i].pos_y)
4714 group->top_y = lines[i].pos_y;
4716 if (group->bot_y < lines[i].max_y)
4717 group->bot_y = lines[i].max_y;
4720 * indicate that this line has been processed already
4722 _DtCvSetProcessed(lines[i]);
4726 /*****************************************************************************
4727 * Function: static _DtCvUnit TestSpacing (
4731 * Returns: True if the object is before (x wise) the test object.
4732 * False if the object is not before (x wise) the text object.
4736 *****************************************************************************/
4746 _DtCvUnit min_space,
4747 _DtCvUnit *ret_amount)
4749 _DtCvStatus result = False;
4752 * check to see if the object is to the left of the test object
4753 * to move and that it 'infringes' on the vertical
4754 * space of the test object.
4756 * I.e. ----obj_top------
4757 * | | ----tst_top----
4758 * ----obj_bot------ | |
4761 * I.e. ----tst_top----
4762 * ----obj_top------- | |
4763 * | | ----tst_bot----
4764 * ----obj_bot-------
4766 * I.e. ----obj_top------
4767 * | | ----tst_top----
4769 * | | ----tst_bot----
4772 * I.e. ----tst_top----
4773 * ----obj_top------- | |
4775 * ----obj_bot------- | |
4778 if (obj_max < tst_min
4779 && True == _DtCvCheckInfringement(tst_top, tst_bot, obj_top, obj_bot)
4780 && needed > tst_min - obj_max)
4783 * okay, this infringes on the object's space.
4784 * truncate the amount of room there is to move the object
4787 needed = tst_min - obj_max;
4790 * is the space between these two objects already squeezed
4791 * below the minimum allowed?
4793 if (needed < min_space)
4795 else /* leave the minimum space between the objects */
4796 needed -= min_space;
4799 *ret_amount = needed;
4803 /*****************************************************************************
4804 * Function: static void MoveLeft (
4810 * Purpose: Moves the object's rules/lines and text lines to the left.
4812 *****************************************************************************/
4815 _DtCanvasStruct *canvas,
4825 * bail now if nothing to do.
4831 * move each text/region line.
4833 for (i = beg_txt; i < end_txt; i++)
4835 canvas->txt_lst[i].text_x -= space;
4836 canvas->txt_lst[i].max_x -= space;
4840 * move each line/rule.
4842 for (i = beg_ln; i < end_ln; i++)
4844 canvas->line_lst[i].pos_x -= space;
4845 canvas->line_lst[i].max_x -= space;
4849 /*****************************************************************************
4850 * Function: static _DtCvUnit CheckSpacing (
4852 * Purpose: Check the spacing before an object and move any objects
4853 * before it to the left to make room.
4855 *****************************************************************************/
4858 _DtCanvasStruct *canvas,
4873 GrpInfo *nxtGrp = layout->grp_lst;
4876 * truncate if the amount needed is more than available.
4884 * see what group is before this group and how much space there is
4886 while (NULL != nxtGrp)
4889 * as long as I'm not comparing against myself, try it.
4891 if (nxtGrp != tst_grp)
4894 * is this group before(x wise) the test group, infringing
4895 * upon the test group's top and bottom positioning (y)
4896 * and is the amount of space (x wise) between them smaller
4897 * than the current smallest space found?
4899 if (True == TestSpacing (top_y, bot_y, min_x,
4900 nxtGrp->top_y, nxtGrp->bot_y,
4901 nxtGrp->max_x, needed,
4902 canvas->metrics.horiz_pad_hint,
4905 space += MoveGroup(canvas, layout, nxtGrp, needed - space);
4906 if (maxSpace > space)
4912 * check the next group
4914 nxtGrp = nxtGrp->next_info;
4918 * look at each of the text lines;
4920 for (i = 0; i < canvas->txt_cnt; i++)
4923 * Only look at those lines not already processed.
4925 if (i != txt_idx && _DtCvIsNotProcessed(canvas->txt_lst[i]))
4927 topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
4928 botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
4929 if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4930 canvas->txt_lst[i].max_x, needed,
4931 canvas->metrics.horiz_pad_hint, &space))
4933 space += MoveText(canvas, layout, i, topY, botY, needed-space);
4934 if (maxSpace > space)
4941 * look at each of the rules/lines;
4943 for (i = 0; i < canvas->line_cnt; i++)
4946 * Only look at those lines not already processed.
4948 if (i != line_idx && _DtCvIsNotProcessed(canvas->line_lst[i]))
4951 * calculate the top and bottom of the line
4953 topY = canvas->line_lst[i].pos_y;
4954 botY = canvas->line_lst[i].max_y;
4956 if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4957 canvas->line_lst[i].max_x, needed,
4958 canvas->metrics.horiz_pad_hint, &space))
4960 space += MoveLines(canvas, layout, i, topY, botY, needed-space);
4961 if (maxSpace > space)
4970 /*****************************************************************************
4971 * Function: static _DtCvUnit MoveGroup (_DtCanvasStruct canvas);
4973 * Purpose: To move groupings (container, tables, etc.) as a group to
4976 *****************************************************************************/
4979 _DtCanvasStruct *canvas,
4987 * find out what's in front of it. And how much 'extra' room
4990 space = CheckSpacing(canvas, layout, tst_grp, -1, -1,
4991 tst_grp->top_y, tst_grp->bot_y, tst_grp->min_x,
4994 * now move the group
4996 MoveLeft(canvas, tst_grp->cnt.beg_txt, tst_grp->cnt.end_txt,
4997 tst_grp->cnt.beg_ln, tst_grp->cnt.end_ln, space);
4999 tst_grp->max_x -= space;
5000 tst_grp->min_x -= space;
5005 /*****************************************************************************
5006 * Function: static _DtCvUnit MoveText (_DtCanvasStruct canvas);
5008 * Purpose: To move text lines to honor boundaries.
5010 *****************************************************************************/
5013 _DtCanvasStruct *canvas,
5023 * find out what's in front of it. And how much 'extra' room
5026 space = CheckSpacing(canvas, layout, NULL, idx, -1,
5028 canvas->txt_lst[idx].text_x,
5031 * now move the group
5033 MoveLeft(canvas, idx, idx, -1, -1, space);
5038 /*****************************************************************************
5039 * Function: static _DtCvUnit MoveLines (_DtCanvasStruct canvas);
5041 * Purpose: To move groupings (container, tables, etc.) as a group to
5044 *****************************************************************************/
5047 _DtCanvasStruct *canvas,
5057 * find out what's in front of it. And how much 'extra' room
5060 space = CheckSpacing(canvas, layout, NULL, -1, idx,
5062 canvas->line_lst[idx].pos_x,
5066 * now move the group
5068 MoveLeft(canvas, -1, -1, idx, idx, space);
5073 /*****************************************************************************
5074 * Function: static void CheckMoveInfo (_DtCanvasStruct canvas);
5076 * Purpose: To move each of the groupings, rules and text lines to
5079 *****************************************************************************/
5082 _DtCanvasStruct *canvas,
5088 _DtCvUnit maxWidth = canvas->metrics.width;
5092 * fill in the max x of each group
5094 for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5097 * find the maximum of the group
5099 MaxOfGroup(nxtGrp, canvas->txt_lst, canvas->line_lst,
5100 layout->info.max_x_pos, layout->info.y_pos);
5104 * now check each group for exceeding the boundary.
5106 for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5109 * does this group exceed the boundary?
5111 if (maxWidth < nxtGrp->max_x)
5112 (void) MoveGroup(canvas, layout, nxtGrp, nxtGrp->max_x - maxWidth);
5116 * look at each of the text lines;
5118 for (i = 0; i < canvas->txt_cnt; i++)
5121 * Only look at those lines not already processed.
5123 if (_DtCvIsNotProcessed(canvas->txt_lst[i]) &&
5124 maxWidth < canvas->txt_lst[i].max_x)
5126 topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
5127 botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
5128 (void) MoveText(canvas, layout, i, topY, botY,
5129 canvas->txt_lst[i].max_x - maxWidth);
5134 * look at each of the rules/lines;
5136 for (i = 0; i < canvas->line_cnt; i++)
5139 * Only look at those lines not already processed.
5141 if (_DtCvIsNotProcessed(canvas->line_lst[i]) &&
5142 maxWidth < canvas->line_lst[i].max_x)
5145 * calculate the top and bottom of the line
5147 topY = canvas->line_lst[i].pos_y;
5148 botY = canvas->line_lst[i].max_y;
5150 (void) MoveLines(canvas, layout, i, topY, botY,
5151 canvas->line_lst[i].max_x - maxWidth);
5156 /*****************************************************************************
5157 * Function: static void CompareUnits ()
5165 *****************************************************************************/
5171 _DtCvUnit *aPtr = (_DtCvUnit *) a;
5172 _DtCvUnit *bPtr = (_DtCvUnit *) b;
5174 if (*aPtr < *bPtr) return -1;
5175 if (*aPtr == *bPtr) return 0;
5180 /*****************************************************************************
5181 * Function: static void CompareSearchs ()
5189 *****************************************************************************/
5195 _DtCvSearchData *searchA = (_DtCvSearchData *) a;
5196 _DtCvSearchData *searchB = (_DtCvSearchData *) b;
5197 _DtCvDspLine *lineA = &(searchA->lst[searchA->idx]);
5198 _DtCvDspLine *lineB = &(searchB->lst[searchB->idx]);
5199 _DtCvUnit topA = lineA->baseline - lineA->ascent;
5200 _DtCvUnit topB = lineB->baseline - lineB->ascent;
5201 _DtCvUnit heightA = lineA->ascent + lineA->descent;
5202 _DtCvUnit heightB = lineB->ascent + lineB->descent;
5203 _DtCvUnit centA = topA + (heightA >> 1);
5204 _DtCvUnit centB = topB + (heightB >> 1);
5206 if (lineA->baseline + lineA->descent < centB && centA < topB)
5209 if (lineB->baseline + lineB->descent < centA && centB < topA)
5212 if (lineA->text_x != lineB->text_x)
5213 return ((lineA->text_x < lineB->text_x) ? -1 : 1);
5216 return ((topA < topB) ? -1 : 1);
5218 if (heightA != heightB)
5219 return ((heightA < heightB) ? -1 : 1);
5221 if (lineA->max_x != lineB->max_x)
5222 return ((lineA->max_x < lineB->max_x) ? -1 : 1);
5227 /*****************************************************************************
5228 * Function: static Status LayoutCanvasInfo (_DtCvHandle canvas);
5236 *****************************************************************************/
5239 _DtCanvasStruct *canvas,
5246 _DtCvUnit maxWidth = 0;
5247 _DtCvUnit maxXPos = 0;
5248 _DtCvStatus result = _DtCvSTATUS_OK;
5251 layout->divisor = divisor;
5252 layout->max_width = canvas->metrics.width;
5253 layout->left = canvas->metrics.side_margin;
5254 layout->right = canvas->metrics.side_margin;
5255 layout->target_id = target_id;
5257 _DtCvInitLayoutInfo(canvas, &(layout->info));
5260 PushDataPoint(layout, &basePt);
5261 SetMargins (layout);
5262 SetTextPosition (layout, True);
5264 ProcessSegmentList(canvas, layout, canvas->element_lst, -1,
5265 &maxWidth, &maxXPos, NULL);
5267 RemoveDataPoint(layout, &basePt);
5270 * fill in the max_x of each line of text/regions.
5272 for (i = 0; i < canvas->txt_cnt; i++)
5273 canvas->txt_lst[i].max_x = MaxXOfLine(canvas, &(canvas->txt_lst[i]));
5276 * calculate the actual right hand side boundary.
5278 layout->info.max_x_pos += canvas->metrics.side_margin;
5281 * the max_x_pos so far has indicated where the *next* character,
5282 * line or region will be *started*. Therefore back up one to
5283 * indicate the true last position used.
5285 layout->info.max_x_pos--;
5289 } /* End LayoutCanvasInfo */
5291 /*****************************************************************************
5292 * Function: static Status LayoutCanvas (_DtCvHandle canvas);
5300 *****************************************************************************/
5303 _DtCanvasStruct *canvas,
5307 _DtCvUnit divisor = 1;
5311 int i, search_cnt = canvas->search_cnt;
5315 result = LayoutCanvasInfo(canvas, layout, divisor, target_id);
5318 * Are we suppose to honor the boundary?
5319 * If so, do any lines go over the boundary?
5320 * Is there any margins that can be decremented?
5322 if (_DtCvSTATUS_OK == result
5323 && (_DtCvUSE_BOUNDARY == canvas->constraint ||
5324 _DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5325 && layout->info.max_x_pos >= canvas->metrics.width)
5327 if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5332 * clear the processed flag from all the text/region lines.
5334 for (i = 0; i < canvas->txt_cnt; i++)
5335 _DtCvClearProcessed(canvas->txt_lst[i]);
5338 * clear the processed flag from all the line/rules.
5340 for (i = 0; i < canvas->line_cnt; i++)
5341 _DtCvClearProcessed(canvas->line_lst[i]);
5343 CheckMoveInfo(canvas, layout);
5346 * recalculate the new max x
5348 layout->info.max_x_pos = 0;
5349 for (i = 0; i < canvas->txt_cnt; i++)
5350 if (layout->info.max_x_pos < canvas->txt_lst[i].max_x)
5351 layout->info.max_x_pos = canvas->txt_lst[i].max_x;
5353 for (i = 0; i < canvas->line_cnt; i++)
5354 if (layout->info.max_x_pos < canvas->line_lst[i].max_x)
5355 layout->info.max_x_pos = canvas->line_lst[i].max_x;
5357 layout->info.max_x_pos--;
5359 else if (True == layout->margin_non_zero)
5363 canvas->txt_cnt = 0;
5364 canvas->line_cnt = 0;
5365 canvas->trav_cnt = 0;
5369 } while (True == redo);
5372 * clean up table information
5374 if (NULL != layout->grp_lst)
5375 free(layout->grp_lst);
5378 * subtract one from the y position to indicate the *last*
5379 * pixel/column/etc that will be rendered.
5381 canvas->max_y = layout->info.y_pos - 1;
5382 canvas->max_x = layout->info.max_x_pos;
5384 for (i = search_cnt; i < canvas->search_cnt; i++)
5386 canvas->searchs[i - search_cnt] = canvas->searchs[i];
5387 canvas->searchs[i - search_cnt].lst = canvas->txt_lst;
5390 canvas->search_cnt -= search_cnt;
5393 * are there any search hits?
5395 if (0 != canvas->search_cnt)
5396 qsort (canvas->searchs, canvas->search_cnt, sizeof(_DtCvSearchData),
5399 * sort the page break list.
5401 if (0 != canvas->brk_cnt)
5402 qsort (canvas->pg_breaks, canvas->brk_cnt, sizeof(_DtCvUnit),
5407 } /* End LayoutCanvas */
5409 /*****************************************************************************
5410 * Function: static void SortTraversal (_DtCvHandle canvas);
5418 *****************************************************************************/
5420 SortTraversal (_DtCanvasStruct *canvas)
5425 * sort the links correctly. First, establish the x,y,width,height
5428 for (i = 0; i < canvas->trav_cnt; i++)
5430 if (_DtCvTraversalLink == canvas->trav_lst[i].type)
5431 GetLinkInfo(canvas, i, &(canvas->trav_lst[i].x_pos),
5432 &(canvas->trav_lst[i].y_pos),
5433 &(canvas->trav_lst[i].width),
5434 &(canvas->trav_lst[i].height));
5436 _DtCvCalcMarkPos(canvas, canvas->trav_lst[i].idx,
5437 &(canvas->trav_lst[i].x_pos),
5438 &(canvas->trav_lst[i].y_pos),
5439 &(canvas->trav_lst[i].width),
5440 &(canvas->trav_lst[i].height));
5443 _DtCvSortTraversalList(canvas, _DtCvFALSE);
5446 /*****************************************************************************
5447 * Function: static void ProcessMarks (_DtCanvasStruct *canvas);
5455 *****************************************************************************/
5458 _DtCanvasStruct *canvas,
5459 _DtCvPointInfo **mark_lst)
5462 int result = _DtCvSTATUS_OK;
5463 _DtCvSelectData beg;
5464 _DtCvSelectData end;
5465 _DtCvSegmentI *firstSeg;
5467 while (NULL != mark_lst && NULL != *mark_lst)
5470 * convert the segments to begin and end points
5472 if (_DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, (*mark_lst)->segs,
5473 &beg, &end, NULL, NULL, &firstSeg))
5475 * just set a return value since this indicates bad data
5476 * and not system failure.
5478 result = _DtCvSTATUS_BAD;
5481 * now add it to the mark list
5485 markIdx = _DtCvAddToMarkList(canvas, (*mark_lst)->client_data,
5486 _DtCvFALSE, &beg, &end);
5488 * now put the mark in the traversal list, but don't sort
5489 * or fill out position and dimension information.
5490 * SortTraversal() will do that.
5492 * bail here if system failure indicated.
5494 if (-1 == markIdx || 0 != _DtCvSetTravEntryInfo(canvas,
5495 _DtCvGetNextTravEntry(canvas),
5496 _DtCvTraversalMark, firstSeg,
5497 markIdx, _DtCvTRUE))
5498 return _DtCvSTATUS_BAD;
5507 /*****************************************************************************
5509 *****************************************************************************/
5510 /*****************************************************************************
5511 * Function: void _DtCanvasResize (_DtCvHandle canvas);
5519 *****************************************************************************/
5522 _DtCvHandle canvas_handle,
5524 _DtCvUnit *ret_width,
5525 _DtCvUnit *ret_height )
5528 _DtCvStatus selectStatus;
5529 _DtCvStatus retStatus = _DtCvSTATUS_NONE;
5530 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
5531 _DtCvUnit oldWidth = canvas->metrics.width;
5533 _DtCvPointInfo selPt;
5534 _DtCvPointInfo **markInfo;
5536 selPt.client_data = NULL;
5540 * check to see if the width has changed - if not,
5541 * don't do anything (but re-initialize the metrics
5542 * to get the new height).
5544 (*(canvas->virt_functions.get_metrics))(canvas->client_data,
5545 _DtCvCANVAS_TYPE, &(canvas->metrics));
5547 if (canvas->metrics.width != oldWidth || _DtCvTRUE == force)
5550 * remember the current selection.
5552 selectStatus = _DtCanvasGetSelectionPoints(canvas, &(selPt.segs),
5555 * remember the marks
5557 if (_DtCvSTATUS_BAD == _DtCvGetMarkSegs(canvas, &markInfo))
5558 return _DtCvSTATUS_BAD;
5561 * Re-Layout the information.
5562 * First step - invalidate some counters.
5564 canvas->trav_cnt = 0; /* zero this only because we re-process */
5565 /* do not zero cur_hyper or we'll loose */
5566 /* where we are in the TOC */
5567 canvas->txt_cnt = 0;
5568 canvas->line_cnt = 0;
5569 canvas->mark_cnt = 0;
5570 canvas->brk_cnt = 0;
5573 * Layout the information if there is anything to do
5575 if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, NULL))
5576 return _DtCvSTATUS_BAD;
5579 * restore the current selection.
5581 if (_DtCvSTATUS_OK == selectStatus)
5583 _DtCanvasActivatePts(canvas,_DtCvACTIVATE_SELECTION, &selPt,
5585 _DtCvFreeArray((void **) selPt.segs);
5589 * now place the marks in the mark and traversal lists
5591 ProcessMarks(canvas, markInfo);
5592 if (NULL != markInfo)
5594 for (i = 0; NULL != markInfo[i]; i++)
5595 _DtCvFreeArray((void **) (markInfo[i]->segs));
5596 _DtCvFreeArray((void **) markInfo);
5600 * sort the traversal list.
5602 SortTraversal(canvas);
5603 retStatus = _DtCvSTATUS_OK;
5607 * return the maximum height and width used
5609 if (ret_width != NULL)
5610 *ret_width = canvas->max_x;
5611 if (ret_height != NULL)
5612 *ret_height = canvas->max_y;
5616 } /* End _DtCanvasResize */
5618 /*****************************************************************************
5619 * Function: void _DtCanvasSetTopic (_DtCvHandle canvas);
5627 *****************************************************************************/
5630 _DtCvHandle canvas_handle,
5631 _DtCvTopicPtr topic,
5632 _DtCvValue honor_size,
5633 _DtCvUnit *ret_width,
5634 _DtCvUnit *ret_height,
5637 _DtCvStatus result = _DtCvSTATUS_OK;
5638 _DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
5644 _DtCanvasClean (canvas_handle);
5647 * attach to the canvas
5649 canvas->element_lst = topic->seg_list;
5652 * Attach the link information
5654 canvas->link_data = topic->link_data;
5657 * init the internal use pointer in all containers to NULL
5659 _DtCvClearInternalUse(canvas->element_lst, _DtCvFALSE);
5662 * Layout the information if there is anything to do
5664 canvas->constraint = honor_size;
5665 if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, topic->id_str))
5666 return _DtCvSTATUS_BAD;
5669 * add the marks to the mark and traversal lists
5671 ProcessMarks(canvas, topic->mark_list);
5674 * sort the traversal list.
5676 SortTraversal(canvas);
5679 * return the maximum height and width used
5680 * And the location of the id.
5682 if (ret_width != NULL)
5683 *ret_width = canvas->max_x;
5684 if (ret_height != NULL)
5685 *ret_height = canvas->max_y;
5688 if (NULL != layOut.target_id && True != layOut.id_found)
5689 result = _DtCvSTATUS_ID_BAD;
5690 *ret_y = layOut.id_Ypos;
5695 } /* End _DtCanvasSetTopic */