1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtHelp/Layout.c
2021-12-24 10:50:27 -07:00

5690 lines
149 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: Layout.c /main/31 1996/10/25 12:00:15 cde-hp $ */
/************************************<+>*************************************
****************************************************************************
**
** File: Layout.c
**
** Project: CDE Info System
**
** Description: Lays out the information on a canvas.
**
** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
**
** (c) Copyright 1993, 1994 Hewlett-Packard Company
** (c) Copyright 1993, 1994 International Business Machines Corp.
** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
** (c) Copyright 1993, 1994 Novell, Inc.
**
**
****************************************************************************
************************************<+>*************************************/
/*
* system includes
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
/*
* Canvas Engine includes
*/
#include "CanvasP.h"
#include "CanvasSegP.h"
/*
* private includes
*/
#include "bufioI.h"
#include "CanvasI.h"
#include "CvStringI.h"
#include "LayoutUtilI.h"
#include "SelectionI.h"
#include "VirtFuncsI.h"
/******************************************************************************
*
* Private Macros
*
*****************************************************************************/
#define ObjHorizOrient(x) (_DtCvContainerOrientOfSeg(x))
#define ObjVertOrient(x) (_DtCvContainerVOrientOfSeg(x))
#define TxtHorizJustify(x) (_DtCvContainerJustifyOfSeg(x))
#define TxtVertJustify(x) (_DtCvContainerVJustifyOfSeg(x))
#define Border(x) (_DtCvContainerBorderOfSeg(x))
#define BrdWidth(x) (_DtCvContainerLineWidthOfSeg(x))
#define BrdData(x) (_DtCvContainerLineDataOfSeg(x))
#define NotJoining(x) (False == (x)->info.join)
#define JoinSet(x) (True == (x)->info.join)
#define CheckAddToHyperList(a, b) \
_DtCvCheckAddHyperToTravList(a, b, _DtCvTRUE, \
&(layout->info.lst_vis), \
&(layout->info.lst_hyper), &(layout->info.cur_len))
/*****************************************************************************
* Private Defines
*****************************************************************************/
/*
* Defines for the dimension arrays
*/
#define DIMS_LEFT 0
#define DIMS_RIGHT 1
#define DIMS_LM 0
#define DIMS_CENTER 1
#define DIMS_RM 2
#define DIMS_TOP 0
#define DIMS_BOTTOM 2
#define DIMS_WIDTH 0
#define DIMS_HEIGHT 1
#define DIMS_YPOS 1
#define DIMS_TC 0
#define DIMS_BC 1
/*
*/
#define GROW_SIZE 10
/******************************************************************************
*
* Private typedefs
*
*****************************************************************************/
/*
* top/bottom dimension array
* -------------------------------------------
* / DIMS_HEIGHT / DIMS_HEIGHT / DIMS_HEIGHT /|
* / DIMS_YPOS / DIMS_YPOS / DIMS_YPOS / |
* /-------------/-------------/-------------/ |
* / DIMS_WIDTH / DIMS_WIDTH / DIMS_WIDTH /| /|
* --------------|-------------|-------------| |/ |
* DIMS_TOP | DIMS_LM | DIMS_CENTER | DIMS_RM | | /|
* |-------------|-------------|-------------|/|/ |
* unused | | | | | /
* |-------------|-------------|-------------|/|/
* DIMS_BOTTOM | DIMS_LM | DIMS_CENTER | DIMS_RM | /
* ------------------------------------------|/
*/
typedef _DtCvUnit TopDims[DIMS_BOTTOM+1][DIMS_RM+1][DIMS_HEIGHT+1];
/*
* left/right side dimension array - contains only the height or y_pos.
* ----------------------------
* DIMS_TOP | DIMS_LEFT | DIMS_RIGHT |
* |------------|-------------|
* DIMS_CENTER | DIMS_LEFT | DIMS_RIGHT |
* |------------|-------------|
* DIMS_BOTTOM | DIMS_LEFT | DIMS_RIGHT |
* ----------------------------
*/
typedef _DtCvUnit SideDims[DIMS_BOTTOM+1][DIMS_RIGHT+1];
/*
* corner dimension array - contains only the height or y_pos.
* ----------------------------
* DIMS_TC | DIMS_LEFT | DIMS_RIGHT |
* |------------|-------------|
* DIMS_BC | DIMS_LEFT | DIMS_RIGHT |
* ----------------------------
*/
typedef _DtCvUnit CornerDims[DIMS_BC+1][DIMS_RIGHT+1];
/*
* flow dimension array
* -------------|--------------
* DIMS_LEFT | DIMS_WIDTH | DIMS_HEIGHT |
* | | DIMS_YPOS |
* |------------|-------------|
* DIMS_RIGHT | DIMS_WIDTH | DIMS_HEIGHT |
* | | DIMS_YPOS |
* ----------------------------
*/
typedef _DtCvUnit FlowDims[DIMS_RIGHT+1][DIMS_HEIGHT+1];
/*
* margin data - important for determining flowing
*/
typedef struct _dataPoint {
_DtCvUnit left;
_DtCvUnit right;
_DtCvUnit y_pos;
_DtCvUnit x_units;
struct _dataPoint *next_pt;
} DataPoint;
/*
* count information
*/
typedef struct _cntInfo {
int beg_txt;
int end_txt;
int beg_ln;
int end_ln;
int my_lines;
int beg_brk;
int end_brk;
} CntInfo;
/*
* group information
*/
typedef struct _grpInfo {
_DtCvUnit min_x;
_DtCvUnit max_x;
_DtCvUnit top_y;
_DtCvUnit bot_y;
CntInfo cnt;
struct _grpInfo *next_info;
} GrpInfo;
/*
* layout information per container
*/
typedef struct _layFrmtInfo {
_DtCvUnit height;
_DtCvUnit width;
CntInfo cnt;
struct _layFrmtInfo *next_info;
} LayFrmtInfo;
/*
* the layout information carried around
*/
typedef struct _layoutInfo {
_DtCvUnit max_width; /* the current max width */
_DtCvUnit id_Ypos; /* the y coordinate of the id found. */
_DtCvUnit left; /* the current left margin for the
current active container (incl br)*/
_DtCvUnit right; /* the current right margin for the
current active container (incl br)*/
_DtCvUnit first; /* the current first indent */
_DtCvUnit lmargin; /* the current absolute left margin */
_DtCvUnit rmargin; /* the current absolute right margin */
_DtCvUnit divisor; /* the current margin divisor */
_DtCvUnit string_end;
_DtCvUnit sub_end;
_DtCvUnit super_end;
_DtCvValue id_found; /* indicates if the id has been found*/
_DtCvValue super_script;
_DtCvValue sub_script;
_DtCvValue stat_flag;
_DtCvValue margin_non_zero;
_DtCvValue brdr_flag; /* within container with a border */
_DtCvValue table_flag; /* within table */
_DtCvFrmtOption txt_justify;
unsigned int cur_start; /* offset into the current segment
to process */
_DtCvSegmentI *lst_rendered; /* indicates the last string/region */
char *target_id; /* if non-null, the id to search for */
DataPoint *data_pts;
GrpInfo *grp_lst; /* list of groups */
_DtCvLayoutInfo info;
} LayoutInfo;
/*
* information for laying out cells in a table.
*/
typedef struct {
int col_spn;
int row_spn;
_DtCvUnit pos_x;
LayFrmtInfo info;
_DtCvSegmentI *cell_seg;
} CellInfo;
/*
* column description information for a table.
*/
typedef struct _columnSpec {
_DtCvUnit min;
_DtCvUnit max;
_DtCvUnit actual;
_DtCvValue hanger;
_DtCvFrmtOption justify;
} ColumnSpec;
/*
* row description information
*/
typedef struct _rowSpec {
int column;
_DtCvUnit y_adj;
_DtCvUnit height;
_DtCvUnit lst_height;
char *next_id;
} RowSpec;
/*****************************************************************************
* Private Variables/Data
*****************************************************************************/
static const LayFrmtInfo DefLayFrmtInfo = { 0, 0, {-1, -1, -1, -1, 0}, NULL };
static const GrpInfo DefGrpInfo = { 0, 0, 0, 0, {-1, -1, -1, -1, 0}};
static const LayoutInfo DefInfo = {
0, /* _DtCvUnit max_width; */
0, /* _DtCvUnit id_Ypos; */
0, /* _DtCvUnit left; */
0, /* _DtCvUnit right; */
0, /* _DtCvUnit first; */
0, /* _DtCvUnit lmargin; */
0, /* _DtCvUnit rmargin; */
1, /* _DtCvUnit divisor; */
0, /* _DtCvUnit string_end; */
0, /* _DtCvUnit sub_end; */
0, /* _DtCvUnit super_end; */
False, /* _DtCvValue id_found; */
False, /* _DtCvValue super_script; */
False, /* _DtCvValue sub_script; */
False, /* _DtCvValue stat_flag; */
False, /* _DtCvValue margin_non_zero; */
False, /* _DtCvValue brdr_flag; */
False, /* _DtCvValue table_flag; */
_DtCvJUSTIFY_LEFT, /* _DtCvFrmtOption txt_justify; */
0, /* unsigned int cur_start; */
NULL, /* _DtCvSegmentI *lst_rendered; */
NULL, /* char *target_id; */
NULL, /* DataPoint *data_pts; */
NULL, /* GrpInfo *data_pts; */
};
static const DataPoint DefDataPt = { 0, 0, _CEFORMAT_ALL, 0, NULL};
static const double HeadDivisor = 10000.0;
static const char *PeriodStr = ".";
static const char *DefWidth[2] = { "", NULL };
static const _DtCvSegmentI BlankTableCell =
{
_DtCvCONTAINER, /* type */
-1, /* link_idx */
{ /* container info */
NULL, /* id */
NULL, /* justify_char */
_DtCvDYNAMIC, /* type */
_DtCvBORDER_NONE, /* border */
_DtCvJUSTIFY_LEFT, /* justify */
_DtCvJUSTIFY_TOP, /* vjustify */
_DtCvJUSTIFY_LEFT, /* orient */
_DtCvJUSTIFY_TOP, /* vorient */
_DtCvWRAP_NONE, /* flow */
0, /* percent */
0, /* leading */
0, /* fmargin */
0, /* lmargin */
0, /* rmargin */
0, /* tmargin */
0, /* bmargin */
_DtCvBORDER_NONE, /* bdr_info */
NULL /* seg_list */
},
NULL, /* next_seg */
NULL, /* next_disp */
NULL, /* client_use */
NULL /* internal_use */
};
/*****************************************************************************
* Private Function Declarations
*****************************************************************************/
static void AdjustForBorders(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption brdr,
_DtCvUnit line_width,
_DtCvUnit *ret_bot,
_DtCvUnit *ret_right);
static void AdjustHeadPosition(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *p_seg,
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow,
LayFrmtInfo *info,
_DtCvUnit base_y,
_DtCvUnit base_left,
_DtCvUnit block_width,
_DtCvUnit left_margin,
_DtCvUnit right_margin);
static void AdjustObjectPosition(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption justify,
int start_txt,
int start_ln,
int start_brk,
int end_txt,
int end_ln,
int end_brk,
int brdr_cnt,
_DtCvUnit height_adj,
_DtCvUnit x_adj,
_DtCvUnit y_adj,
_DtCvUnit internal_y);
static void CheckSaveInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *new_seg,
int start);
static void DetermineFlowConstraints(
LayoutInfo *layout,
FlowDims flow_dims,
_DtCvUnit left_margin,
_DtCvUnit right_margin,
_DtCvUnit start_y,
DataPoint *left_pt,
DataPoint *right_pt);
static void DetermineHeadPositioning(
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow,
_DtCvUnit start_y,
_DtCvUnit max_top,
_DtCvUnit block_size,
_DtCvUnit *ret_side_size);
static void DetermineMaxDims(
TopDims *top_bot,
CornerDims *corner,
_DtCvUnit left_margin,
_DtCvUnit right_margin,
_DtCvUnit *top_height,
_DtCvUnit *bot_height,
_DtCvUnit *max_width);
static int DrawBorders(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption brdr,
_DtCvPointer data,
_DtCvUnit line_width,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit left_x,
_DtCvUnit right_x);
static void FormatCell(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cell_seg,
_DtCvUnit span_width,
_DtCvUnit min_height,
DataPoint base_pt,
int *ret_ln,
_DtCvUnit *ret_width,
_DtCvUnit *ret_height,
_DtCvValue *ret_tab_flag);
static void InitDimArrays(
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow);
static _DtCvStatus LayoutCanvasInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvUnit divisor,
char *target_id);
static _DtCvValue LinesMayChange(
_DtCanvasStruct *canvas,
int start_ln,
int end_ln,
int brdr_cnt);
static _DtCvUnit MoveGroup (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
GrpInfo *tst_grp,
_DtCvUnit needed);
static _DtCvUnit MoveLines (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
int idx,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit needed);
static _DtCvUnit MoveText (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
int idx,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit needed);
static void ProcessContainer(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *con_seg,
_DtCvUnit min_y,
_DtCvUnit *ret_width,
_DtCvUnit *ret_max_x,
int *ret_cnt);
static void ProcessSegmentList(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cur_seg,
_DtCvUnit min_y,
_DtCvUnit *ret_width,
_DtCvUnit *ret_max_x,
int **ret_vert);
/******************************************************************************
*
* Private Functions
*
*****************************************************************************/
/******************************************************************************
* Function: AdjustTextPositions
*
* changes the baseline and text_x positioning of the text line by the
* offsets indicated.
*****************************************************************************/
static void
AdjustTextPositions(
_DtCanvasStruct *canvas,
int beg,
int end,
_DtCvUnit x_offset,
_DtCvUnit y_offset)
{
if ( 0 != y_offset || 0 != x_offset)
{
while (beg < end)
{
canvas->txt_lst[beg].baseline += y_offset;
canvas->txt_lst[beg].text_x += x_offset;
beg++;
}
}
}
/******************************************************************************
* Function: AdjustLinePositions
*
* changes the x & positions and the max x & y values by the offsets indicated.
*****************************************************************************/
static void
AdjustLinePositions(
_DtCanvasStruct *canvas,
int beg,
int end,
_DtCvUnit x_offset,
_DtCvUnit y_offset)
{
if ( 0 != y_offset || 0 != x_offset)
{
while (beg < end)
{
canvas->line_lst[beg].pos_y += y_offset;
canvas->line_lst[beg].max_y += y_offset;
canvas->line_lst[beg].pos_x += x_offset;
canvas->line_lst[beg].max_x += x_offset;
beg++;
}
}
}
/******************************************************************************
* Function: AdjustPgBrk
*
* changes the y position of a page break.
*****************************************************************************/
static void
AdjustPgBrk(
_DtCanvasStruct *canvas,
int beg,
int end,
_DtCvUnit y_offset)
{
if (0 != y_offset)
{
while (beg < end)
canvas->pg_breaks[beg++] += y_offset;
}
}
/******************************************************************************
* Function: MaxXOfLine
*
* MaxXOfLine determines the max X of a line segment.
*
*****************************************************************************/
/******************************************************************************
* Function: MaxXOfLine
*
* MaxXOfLine determines the max X of a line segment.
*
*****************************************************************************/
static _DtCvUnit
MaxXOfLine(
_DtCanvasStruct *canvas,
_DtCvDspLine *line)
{
_DtCvValue lastLinkVisible = FALSE;
int count = line->length;
int start = line->byte_index;
int len;
int lnkInd = -1;
_DtCvUnit xPos;
_DtCvUnit tmpWidth;
_DtCvSegmentI *pSeg;
xPos = _DtCvGetStartXOfLine(line, &pSeg);
while (pSeg != NULL && count > 0)
{
xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
&lnkInd, &lastLinkVisible);
_DtCvGetWidthOfSegment(canvas, pSeg, start, count,
&len, &tmpWidth, NULL);
xPos += tmpWidth;
count -= len;
start = 0;
pSeg = pSeg->next_disp;
}
return xPos;
} /* End MaxXOfLine */
/*****************************************************************************
* Function: void GetLinkInfo ()
*
* Parameters:
* canvas Specifies the handle for the canvas.
*
* Returns: A handle to the canvas or NULL if an error occurs.
*
* Purpose:
*
*****************************************************************************/
static _DtCvValue
GetLinkInfo (
_DtCvHandle canvas_handle,
int indx,
_DtCvUnit *ret_x,
_DtCvUnit *ret_y,
_DtCvUnit *ret_width,
_DtCvUnit *ret_height)
{
int len;
int line;
int count;
int startChar;
int lnkIndx = -1;
_DtCvUnit startX;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvSegmentI *pSeg;
_DtCvValue lstVisible = False;
_DtCvValue found = False;
_DtCvValue junk;
_DtCvUnit endX = 0;
void *pChar;
/*
* get the line index
*/
line = canvas->trav_lst[indx].idx;
/*
* get some information from the line
*/
pSeg = canvas->txt_lst[line].seg_ptr;
count = canvas->txt_lst[line].length;
startChar = canvas->txt_lst[line].byte_index;
startX = canvas->txt_lst[line].text_x;
*ret_y = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
*ret_height = canvas->txt_lst[line].ascent + canvas->txt_lst[line].descent;
while (count > 0 && !found && pSeg != NULL)
{
if (startX < canvas->txt_lst[line].text_x)
startX = canvas->txt_lst[line].text_x;
/*
* adjust the starting position by the link space
*/
junk = _DtCvIsSegVisibleLink(pSeg);
lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg, junk,
lstVisible, lnkIndx, &startX);
/*
* adjust the starting position by the traversal space
*/
junk = _DtCvIsSegALink(pSeg);
(void) _DtCvModifyXpos (canvas->traversal_info, pSeg, junk,
((_DtCvValue) True), lnkIndx, &startX);
lnkIndx = pSeg->link_idx;
/*
* skip no-op
*/
if (_DtCvIsSegNoop(pSeg))
len = 0;
/*
* check region
*/
else if (_DtCvIsSegRegion(pSeg))
{
len = 1;
endX = startX + _DtCvWidthOfRegionSeg(pSeg);
}
else
{
/*
* initialize the pointer to the string
*/
pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
_DtCvIsSegWideChar(pSeg), startChar);
/*
* get the length of the current string.
* If it is longer than the line count indicates,
* it must be wrapped to the next line. We are
* only interested in in the part of the line
* that is on the line selected.
*/
len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
if (len > count)
len = count;
/*
* calculate the ending pixel postion for
* this string segment.
*/
endX = startX + _DtCvGetStringWidth(canvas,pSeg,pChar,len);
}
/*
* test to see if the selected segment was this segment.
*/
if (pSeg == canvas->trav_lst[indx].seg_ptr)
{
found = True;
*ret_x = startX;
*ret_width = endX - startX;
}
else
{
/*
* go to the next segment.
*/
pSeg = pSeg->next_disp;
/*
* adjust for the new begining.
*/
startX = endX;
count = count - len;
startChar = 0;
}
}
return found;
}
/******************************************************************************
* Function: CheckId
*
* Check to see if the id matches the target id.
* If so, set the 'found id' flag and indicate its y coordinate.
*****************************************************************************/
static void
CheckId(
LayoutInfo *layout,
char *id)
{
if (layout->target_id != NULL && NULL != id &&
_DtCvStrCaseCmpLatin1(id, layout->target_id) == 0)
{
layout->id_Ypos = layout->info.y_pos;
layout->id_found = True;
}
}
/******************************************************************************
* Function: CheckSetLineStart
*
* Check to see if the line information is at the beginning.
* If so, set the pointers to the current segment and offset.
*****************************************************************************/
static void
CheckSetLineStart(
LayoutInfo *layout,
_DtCvSegmentI *cur_seg)
{
if (layout->info.line_bytes == 0)
{
layout->info.line_seg = cur_seg;
layout->info.line_start = 0;
}
}
/******************************************************************************
* Function: CheckForPageBreak
*
* Check to see if there is a page break on this segment.
* If so, remember its position.
*****************************************************************************/
static int
CheckForPageBreak(
_DtCanvasStruct *canvas,
_DtCvSegmentI *cur_seg,
_DtCvUnit position)
{
/*
* does this segment cause a page break?
*/
if (_DtCvIsSegPageBreak(cur_seg))
{
/*
* check to see if there is room to save the page break.
* if not, allocate more room.
*/
if (canvas->brk_cnt >= canvas->brk_max)
{
canvas->brk_max += GROW_SIZE;
if (NULL != canvas->pg_breaks)
canvas->pg_breaks = (_DtCvUnit *) realloc (
(void *) canvas->pg_breaks,
(sizeof(_DtCvUnit) * canvas->brk_max));
else
canvas->pg_breaks = (_DtCvUnit *) malloc (
(sizeof(_DtCvUnit) * canvas->brk_max));
}
/*
* failed to allocate memory, abort.
*/
if (NULL == canvas->pg_breaks)
{
canvas->brk_max = 0;
canvas->brk_cnt = 0;
return 1;
}
/*
* save the y position of the page break for later.
*/
canvas->pg_breaks[canvas->brk_cnt++] = position;
}
return 0;
}
/******************************************************************************
* Function: SetBeginCounts
*
* Parameters:
* canvas Specifies the canvas.
* f_info Specifies the layout count info.
*
* Returns: Nothing
*
* Purpose: Initializes the layout count information for a container.
*****************************************************************************/
static void
SetBeginCounts (
_DtCanvasStruct *canvas,
CntInfo *cnt_info)
{
/*
* text counts
*/
cnt_info->beg_txt = canvas->txt_cnt;
cnt_info->end_txt = canvas->txt_cnt;
/*
* line counts
*/
cnt_info->beg_ln = canvas->line_cnt;
cnt_info->end_ln = canvas->line_cnt;
/*
* break counts
*/
cnt_info->beg_brk = canvas->brk_cnt;
cnt_info->end_brk = canvas->brk_cnt;
}
/******************************************************************************
* Function: SetEndCounts
*
* Parameters:
* canvas Specifies the canvas.
* f_info Specifies the layout count info.
*
* Returns: Nothing
*
* Purpose: Sets the ending layout counts for a container.
*****************************************************************************/
static void
SetEndCounts (
_DtCanvasStruct *canvas,
CntInfo *cnt_info,
int end_ln)
{
/*
* text counts
*/
cnt_info->end_txt = canvas->txt_cnt;
/*
* line counts
*/
cnt_info->end_ln = canvas->line_cnt;
/*
* break counts
*/
cnt_info->end_brk = canvas->brk_cnt;
/*
* the number of lines for this container.
* If negative, indicates the first line is for the
* bottom of the container and goes the length.
*/
cnt_info->my_lines = end_ln;
}
/******************************************************************************
* Function: SkipToNumber
*
* Returns:
*****************************************************************************/
static void
SkipToNumber (
const char **string)
{
if (string != NULL)
{
const char *str = *string;
while (*str == ' ' && *str != '\0')
str++;
*string = str;
}
}
/******************************************************************************
* Function: GetValueFromString
*
* Returns:
*****************************************************************************/
static int
GetValueFromString (
const char **string,
int def_num)
{
int value = def_num;
if (string != NULL && *string != NULL && **string != '\0')
{
const char *str = *string;
if ('0' <= *str && *str <= '9')
value = atoi(str);
while ('0' <= *str && *str <= '9')
str++;
while (*str != ' ' && *str != '\0' && (*str < '0' || *str > '9'))
str++;
*string = str;
}
return value;
}
/******************************************************************************
* Function: PushDataPoint
*
* Returns:
*****************************************************************************/
static void
PushDataPoint (
LayoutInfo *layout,
DataPoint *data_pt)
{
data_pt->x_units = 0;
data_pt->next_pt = layout->data_pts;
layout->data_pts = data_pt;
}
/******************************************************************************
* Function: InsertDataPoint
*
* Returns:
*****************************************************************************/
static void
InsertDataPoint (
LayoutInfo *layout,
DataPoint *data_pt)
{
DataPoint *lastPt = NULL;
DataPoint *nextPt = layout->data_pts;
while (nextPt != NULL &&
nextPt->y_pos != _CEFORMAT_ALL &&
(data_pt->y_pos == _CEFORMAT_ALL || nextPt->y_pos < data_pt->y_pos))
{
lastPt = nextPt;
nextPt = nextPt->next_pt;
}
data_pt->next_pt = nextPt;
data_pt->x_units = 0;
if (lastPt == NULL)
layout->data_pts = data_pt;
else
lastPt->next_pt = data_pt;
}
/******************************************************************************
* Function: RemoveDataPoint
*
* Returns:
*****************************************************************************/
static void
RemoveDataPoint (
LayoutInfo *layout,
DataPoint *data_pt)
{
DataPoint *lastPt = NULL;
DataPoint *curPt = layout->data_pts;
while (curPt != NULL && curPt != data_pt)
{
lastPt = curPt;
curPt = curPt->next_pt;
}
if (curPt != NULL)
{
data_pt->x_units = layout->info.cur_max_x - data_pt->left;
if (lastPt == NULL)
layout->data_pts = curPt->next_pt;
else
lastPt->next_pt = curPt->next_pt;
}
}
/******************************************************************************
* Function: GetCurrentDataPoint
*
* Returns:
*****************************************************************************/
static void
GetCurrentDataPoint (
LayoutInfo *layout,
DataPoint *data_pt)
{
data_pt->left = 0;
data_pt->right = 0;
data_pt->y_pos = _CEFORMAT_ALL;
if (layout->data_pts != NULL)
*data_pt = *(layout->data_pts);
}
/******************************************************************************
* Function: SetMargins
*
* Purpose: Sets the margins.
*****************************************************************************/
static void
SetMargins (
LayoutInfo *layout)
{
layout->lmargin = 0;
layout->rmargin = 0;
layout->info.format_y = _CEFORMAT_ALL;
if (layout->data_pts != NULL)
{
/*
* base
*/
layout->lmargin = layout->data_pts->left;
layout->rmargin = layout->data_pts->right;
layout->info.format_y = layout->data_pts->y_pos;
}
layout->lmargin += layout->left;
layout->rmargin += layout->right;
}
/******************************************************************************
* Function: SetTextPosition
*
* Purpose: Sets the text beginning position to the left margin.
* If 'first' is true, adds its value to the text beginning
* position value.
*****************************************************************************/
static void
SetTextPosition (
LayoutInfo *layout,
_DtCvValue first)
{
layout->info.text_x_pos = layout->lmargin;
if (first == True)
layout->info.text_x_pos += layout->first;
}
/******************************************************************************
* Function: CheckFormat
*
* Purpose: Checks to see if the flowing txt boundaries have been exceeded.
* If a boundary has been exceeded, then removes that boundary
* information from the stack until it finds a valid boundary point.
*
* Calls SetMargins to set the correct margin
* Calls SetTextPosition to set the text beginning position.
*****************************************************************************/
static void
CheckFormat (
LayoutInfo *layout,
_DtCvValue first)
{
while (layout->data_pts != NULL &&
layout->data_pts->y_pos != _CEFORMAT_ALL &&
layout->data_pts->y_pos < layout->info.y_pos)
RemoveDataPoint (layout, layout->data_pts);
SetMargins(layout);
SetTextPosition(layout, first);
}
/******************************************************************************
* Function: SaveLine
*
* Initializes a line table element to the segment it should display.
*****************************************************************************/
static void
SaveLine (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
int direction,
_DtCvPointer data,
_DtCvUnit line_width,
_DtCvUnit x,
_DtCvUnit y,
_DtCvUnit length)
{
int i = canvas->line_cnt;
_DtCvUnit x2 = x;
_DtCvUnit y2 = y;
if (i >= canvas->line_max)
{
canvas->line_max += GROW_SIZE;
if (canvas->line_lst)
canvas->line_lst = (_DtCvLineSeg *) realloc (
(void *) canvas->line_lst,
(sizeof(_DtCvLineSeg) * canvas->line_max));
else
canvas->line_lst = (_DtCvLineSeg *) malloc (
(sizeof(_DtCvLineSeg) * canvas->line_max));
/*
* NOTE....should this routine return a value?
* If (re)alloc error occurs, this simply ignores the problem.
*/
if (canvas->line_lst == NULL)
{
canvas->line_max = 0;
canvas->line_cnt = 0;
return;
}
}
/*
* does this line exceed the current maximum?
*/
if (_DtCvLINE_HORZ == direction)
{
x2 += length;
y2 += line_width;
}
else
{
x2 += line_width;
y2 += length;
}
if (layout->info.max_x_pos < x2)
layout->info.max_x_pos = x2;
if (layout->info.cur_max_x < x2)
layout->info.cur_max_x = x2;
/*
* save the line information
*/
canvas->line_lst[i].dir = direction;
canvas->line_lst[i].pos_x = x;
canvas->line_lst[i].max_x = x2;
canvas->line_lst[i].pos_y = y;
canvas->line_lst[i].max_y = y2;
canvas->line_lst[i].width = line_width;
canvas->line_lst[i].data = data;
canvas->line_cnt++;
}
/******************************************************************************
* Function: SaveInfo
*
* Purpose: Saves the current information into the txt line struct.
* Checks to see if this line exceeds the flowing text
* boundary and resets the internal global margins.
*****************************************************************************/
static void
SaveInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *new_seg,
int start)
{
_DtCvSaveInfo (canvas, &(layout->info),
layout->max_width, layout->rmargin, layout->txt_justify);
while (layout->info.delayed_search_saves > 0) {
_DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
layout->info.delayed_search_saves--;
}
layout->super_end = 0;
layout->sub_end = 0;
layout->super_script = False;
layout->sub_script = False;
layout->info.line_seg = new_seg;
layout->info.line_start = start;
layout->info.cur_len = 0;
CheckFormat(layout, FALSE);
}
/******************************************************************************
* Function: CheckSaveInfo
*
* Purpose: Checks to see if there is any information to save and saves
* it if there is any.
*****************************************************************************/
static void
CheckSaveInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *new_seg,
int start)
{
if (layout->info.line_bytes)
SaveInfo (canvas, layout, new_seg, start);
}
/******************************************************************************
* Function: ProcessStringSegment
*
* chops a string segment up until its completely used.
*
*****************************************************************************/
static void
ProcessStringSegment(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cur_seg)
{
layout->cur_start = 0;
if (!(_DtCvIsSegSuperScript(cur_seg) || _DtCvIsSegSubScript(cur_seg))
&& (layout->super_script == True || layout->sub_script == True))
{
layout->super_end = 0;
layout->sub_end = 0;
layout->super_script = False;
layout->sub_script = False;
}
while (_DtCvProcessStringSegment(canvas, &(layout->info),
layout->max_width, layout->lmargin, layout->rmargin,
cur_seg , &(layout->cur_start),
layout->txt_justify, layout->stat_flag) == 1)
CheckFormat(layout, False);
} /* End ProcessStringSegment */
/******************************************************************************
* Function: _DtCvUnit ResolveHeight(
*
* Parameters:
*
* Purpose: Determines the height of a row that is spanned.
*****************************************************************************/
static _DtCvUnit
ResolveHeight(
RowSpec *row_info,
CellInfo *cell_info,
int max_cols,
int row,
int span)
{
int i;
int col;
int cell;
int topRow;
int topCell;
int zeroed;
int total;
int rowHeight = 0;
for (col = 0, cell = row * max_cols; col < max_cols; col++, cell++)
{
/*
* if we have a row spanning cell in this column,
* but it isn't from a previous column, try to fill out
* the height using it.
*/
if (cell_info[cell].row_spn == -1 && cell_info[cell].col_spn != -1)
{
/*
* back up to the cell information containing the row
* span value.
*/
topRow = row;
topCell = cell;
do
{
topCell--;
topRow--;
} while (cell_info[topCell].row_spn == -1);
/*
* from here, start calculating the height of the row
* spanning cell, and find out how big the row must
* be to contain it.
*/
i = cell_info[topCell].row_spn;
zeroed = span + 1;
total = 0;
while (i > 0 && zeroed > 0)
{
total += row_info[topRow].height;
if (row_info[topRow].height == 0)
zeroed--;
i--;
topRow++;
}
/*
* if zeroed is greater than zero, that means only the
* allowd number of row heights were zeroed out (the ones
* we are looking for).
* go ahead and calculate a new height. Otherwise,
* it may be tried later.
*/
if (zeroed > 0)
{
/*
* make sure we get a positive value out of
* this for our height.
*/
if (cell_info[topCell].info.height > total)
{
total = cell_info[topCell].info.height - total;
total = total / span + (total % span ? 1 : 0);
}
/*
* make sure we take the biggest value possible
* for this row. If it needs to be smaller for
* cells, we'll adjust the positioning within
* the cell.
*/
if (rowHeight < total)
rowHeight = total;
}
}
}
row_info[row].height = rowHeight;
return rowHeight;
}
/******************************************************************************
* Function: void AdjustHeight(
*
* Parameters:
*
* Purpose: Determines the height of rows that are spanned but the
* the spanner needs more room than the calculated row height
* allow.
*****************************************************************************/
static void
AdjustHeight(
CellInfo *cell_info,
RowSpec *row_specs,
int max_cols,
int row,
int col)
{
int cell = row * max_cols + col;
int i, j;
_DtCvUnit total;
_DtCvUnit adjustValue;
_DtCvUnit value;
if (cell_info[cell].col_spn == -1 || cell_info[cell].row_spn == -1)
return;
for (j = row, i = 0, total = 0; i < cell_info[cell].row_spn; i++, j++)
total += row_specs[j].height;
/*
* adjust the row height to include all of the row spanning cell.
*/
if (total < cell_info[cell].info.height)
{
_DtCvUnit totalUsed = 0;
/*
* first, try to grow the cells on a percentage basis.
* This way, a small cell will grow the same amount relative
* to the larger cells.
*/
adjustValue = cell_info[cell].info.height - total;
/*
* now if total is zero, we'll get a divide by zero error.
* So check for this and set total to the number of rows spanned.
*/
if (0 == total)
total = cell_info[cell].row_spn;
for (i = 0; i < cell_info[cell].row_spn; i++)
{
value = (((row_specs[row + i].height * 100) / total) * adjustValue)
/ 100;
row_specs[row + i].height += value;
totalUsed += value;
}
/*
* if didn't use all the size up - apply it evenly.
*/
if (totalUsed < adjustValue)
{
adjustValue = adjustValue - totalUsed;
for (i = 0, j = cell_info[cell].row_spn;
adjustValue > 0 && i < cell_info[cell].row_spn; i++, j--)
{
value = adjustValue / j + (adjustValue % j ? 1 : 0);
row_specs[row + i].height += value;
adjustValue -= value;
totalUsed += value;
}
}
total = totalUsed;
}
}
/******************************************************************************
* Function: void ReFormatCell(
*
* Parameters:
* canvas Specifies the specific information about the
* rendering area.
* layout Specifies the currently active information
* affecting the layout of information.
*
* Purpose: Based on a height and width, relay out the information in a cell.
*****************************************************************************/
static void
ReFormatCell(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
CellInfo *this_cell,
ColumnSpec *col_specs,
int col,
_DtCvUnit new_height,
_DtCvUnit new_y)
{
int i;
int saveTxt = canvas->txt_cnt;
int saveLn = canvas->line_cnt;
_DtCvUnit saveYpos = layout->info.y_pos;
_DtCvUnit saveMaxX = layout->info.cur_max_x;
_DtCvUnit cellWidth = 0;
_DtCvUnit junk;
_DtCvValue junkValue;
DataPoint basePt;
/*
* reset the y_pos to the correct placement.
* reset the line counts to the original values.
* since we aren't changing the width, the number
* of lines used will not change.
*/
layout->info.y_pos = new_y;
canvas->txt_cnt = this_cell->info.cnt.beg_txt;
canvas->line_cnt = this_cell->info.cnt.beg_ln;
/*
* determine the maximum width for the cell.
*/
for (i = this_cell->col_spn; i > 0; i--)
cellWidth += col_specs[col++].actual;
/*
* get the current left and right margins.
*/
GetCurrentDataPoint(layout, &basePt);
/*
* re-format the cell
*/
FormatCell(canvas, layout, this_cell->cell_seg, cellWidth,
new_height,
basePt, &i, &cellWidth, &junk, &junkValue);
/*
* calculate the new height.
*/
this_cell->info.height = layout->info.y_pos - new_y;
/*
* if the new cell does not use the same number of lines as the
* old formatting did, zero the length.
*/
while (canvas->txt_cnt < this_cell->info.cnt.end_txt)
canvas->txt_lst[canvas->txt_cnt++].length = 0;
/*
* restore the saved counters
*/
canvas->txt_cnt = saveTxt;
canvas->line_cnt = saveLn;
layout->info.y_pos = saveYpos;
layout->info.cur_max_x = saveMaxX;
}
/******************************************************************************
* Function: void FormatCell(
*
* Parameters:
* canvas Specifies the specific information about the
* rendering area.
* layout Specifies the currently active information
* affecting the layout of information.
* span_width Specifies the desired size constraining
* the layout of information.
* base_pt Specifies the base margins.
* this_cell Specifies the cell structure to fill out.
*
* Purpose: Determines the width and height of the cell. Also the begin/end
* counts on text, graphics and lines.
*****************************************************************************/
static void
FormatCell(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cell_seg,
_DtCvUnit span_width,
_DtCvUnit min_height,
DataPoint base_pt,
int *ret_ln,
_DtCvUnit *ret_width,
_DtCvUnit *ret_height,
_DtCvValue *ret_tab_flag)
{
_DtCvStatus only1Col = True;
_DtCvUnit maxX;
_DtCvUnit minY = -1;
_DtCvUnit saveYpos = layout->info.y_pos;
_DtCvUnit saveRight = layout->right;
_DtCvUnit saveMaxX = layout->info.cur_max_x;
_DtCvSegmentI *nextSeg;
/*
* set the limits/margins
* assume the left_margin has been set by a previous call.
*/
layout->right = layout->max_width - base_pt.left - base_pt.right
- layout->left - span_width;
/*
* set the minimum Y for the container.
*/
if (0 < min_height)
minY = saveYpos + min_height;
/*
* If a segment was specified for this cell, format it.
*/
if (cell_seg != NULL && &BlankTableCell != cell_seg)
{
ProcessContainer(canvas, layout, cell_seg, minY,
ret_width, &maxX, ret_ln);
/*
* check to see if the only thing in this container is a
* table.
*/
nextSeg = _DtCvContainerListOfSeg(cell_seg);
*ret_tab_flag = True;
while (True == *ret_tab_flag && NULL != nextSeg)
{
/*
* check to see if there is any segments that aren't one
* column tables.
*/
if (_DtCvIsSegTable(nextSeg) &&
1 < _DtCvNumColsOfTableSeg(nextSeg))
only1Col = False;
else if (!(_DtCvIsSegTable(nextSeg) || _DtCvIsSegNoop(nextSeg)))
*ret_tab_flag = False;
nextSeg = _DtCvNextSeg(nextSeg);
}
if (True == *ret_tab_flag && True == only1Col)
*ret_tab_flag = False;
}
/*
* Calculate the height and return it.
*/
*ret_height = layout->info.y_pos - saveYpos;
/*
* restore the right margin
*/
layout->right = saveRight;
if (layout->info.cur_max_x < saveMaxX)
layout->info.cur_max_x = saveMaxX;
}
/******************************************************************************
* Function: AdjustFrmtTxtOption
*
*****************************************************************************/
static void
AdjustFrmtTxtOption(
_DtCvSegmentI *p_seg,
_DtCvFrmtOption option)
{
if (p_seg != NULL && _DtCvIsSegContainer(p_seg))
{
TxtHorizJustify(p_seg) = option;
p_seg = _DtCvContainerListOfSeg(p_seg);
while (p_seg != NULL)
{
AdjustFrmtTxtOption(p_seg, option);
p_seg = p_seg->next_seg;
}
}
}
/******************************************************************************
* Function: ResolveCell
*
*****************************************************************************/
static _DtCvValue
ResolveCell(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *table,
ColumnSpec *col_specs,
RowSpec *row_specs,
int col,
int row,
int max_cols,
int max_rows,
CellInfo *ret_info)
{
int i;
char *id = NULL;
char *idRefs;
char *ptr = NULL;
char c = 0;
int count;
int len;
int done;
int brdCnt;
int myCol = col;
int cell = row * max_cols + col;
_DtCvUnit cellWidth;
_DtCvUnit retWidth;
_DtCvUnit retHeight;
_DtCvUnit saveTop = 0;
CellInfo *thisCell = &ret_info[cell];
DataPoint basePt;
_DtCvValue reformat = False;
_DtCvValue retTabFlag = False;
_DtCvSegmentI **f_data = _DtCvCellsOfTableSeg(table);
/*
* if this column is spanned, skip
*/
if (thisCell->col_spn == -1 || thisCell->row_spn == -1)
return False;
GetCurrentDataPoint(layout, &basePt);
if (thisCell->cell_seg == NULL)
{
idRefs = row_specs[row].next_id;
/*
* find the end of the id
*/
done = False;
/*
* set the starting info
*/
thisCell->col_spn = 1;
thisCell->pos_x = basePt.left + layout->left;
while (!done && col < max_cols)
{
ptr = idRefs;
id = idRefs;
/*
* move the ptr to the next id,
* counting the characters in this id at the same time.
*/
len = 0;
while (NULL != ptr && *ptr != ' ' && *ptr != '\0')
{
ptr++;
len++;
}
/*
* set idRefs to the next id.
*/
idRefs = ptr;
while (NULL != idRefs && *idRefs == ' ')
idRefs++;
/*
* Is this id and the next the same? If so,
* it spans the columns
*/
if (0 != len && _DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
(idRefs[len] == ' ' || idRefs[len] == '\0'))
{
col++;
thisCell->col_spn++;
ret_info[++cell].col_spn = -1;
}
else
done = True;
}
row_specs[row].next_id = idRefs;
/*
* find the segment
*/
if (NULL != id && '\0' != *id)
{
c = *ptr;
*ptr = '\0';
while (f_data != NULL && NULL != *f_data &&
_DtCvStrCaseCmpLatin1(_DtCvContainerIdOfSeg(*f_data),id) != 0)
f_data++;
/*
* make sure to break the link to the next segment.
* Otherwise, the formatting routines will format too much
* for the cell.
*/
if (NULL != f_data && NULL != *f_data)
{
_DtCvNextSeg(*f_data) = NULL;
/*
* assign the data to this cell.
*/
thisCell->cell_seg = *f_data;
}
else /* there is no id for this cell, use a blank container */
thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
}
else /* there is no id for this cell, use a blank container */
thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
/*
* how many rows does this cell span?
*/
len = 0;
if (NULL != id)
len = strlen(id);
for (done = False, count = 1, i = row + 1;
0 < len && i < max_rows && False == done; i++)
{
done = True;
if (_DtCvStrNCaseCmpLatin1(id, row_specs[i].next_id, len) == 0 &&
(row_specs[i].next_id[len] == ' ' ||
row_specs[i].next_id[len] == '\0'))
{
int k;
done = False;
count++;
/*
* invalidate the columns spanned in this row
*/
for (k = 0; k < thisCell->col_spn && k + myCol < max_cols; k++)
{
ret_info[i * max_cols + myCol + k].col_spn = -1;
ret_info[i * max_cols + myCol + k].row_spn = -1;
}
idRefs = row_specs[i].next_id;
do
{
/*
* skip the current id.
*/
while (*idRefs != ' ' && *idRefs != '\0')
idRefs++;
/*
* skip the space to the next id.
*/
while (*idRefs == ' ')
idRefs++;
/*
* now test to see if this is a match
* cycle if so. quit if the end of string
* or not a match.
*/
} while (*idRefs != '\0' &&
_DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
(idRefs[len] == ' ' || idRefs[len] == '\0'));
/*
* the next non-spanned column in this row will use this id.
*/
row_specs[i].next_id = idRefs;
}
}
if (NULL != id && '\0' != *id)
*ptr = c;
thisCell->row_spn = count;
}
for (i = 0, cellWidth = 0; i < thisCell->col_spn; i++)
cellWidth += col_specs[myCol + i].actual;
/*
* set the start line and text information
*/
SetBeginCounts(canvas, &(thisCell->info.cnt));
/*
* check to see if this cell is overhung by a previous cell.
* If so, zero the top margin. But remember and restore it
* because resizing may eliminate the need for the overhang!
*/
if (&BlankTableCell != thisCell->cell_seg)
{
saveTop = _DtCvContainerTMarginOfSeg(thisCell->cell_seg);
if (_DtCvTRUE == col_specs[myCol].hanger
&& 0 != row_specs[row].y_adj && myCol > row_specs[row].column)
_DtCvContainerTMarginOfSeg(thisCell->cell_seg) = 0;
}
/*
* Format the cell
*/
FormatCell(canvas, layout, thisCell->cell_seg, cellWidth,
row_specs[row].height, basePt,
&brdCnt, &retWidth, &retHeight, &retTabFlag);
if (&BlankTableCell != thisCell->cell_seg)
_DtCvContainerTMarginOfSeg(thisCell->cell_seg) = saveTop;
/*
* set some ending information
*/
thisCell->info.height = retHeight;
thisCell->info.width = retWidth;
SetEndCounts(canvas, &(thisCell->info.cnt), brdCnt);
/*
* check the height against previous heights
*/
if (row_specs[row].height < retHeight && thisCell->row_spn == 1)
row_specs[row].height = retHeight;
/*
* check for run over of the desired widths
*/
if (retWidth > cellWidth)
{
int j;
_DtCvUnit cellMax;
_DtCvUnit maxSlop;
_DtCvUnit value;
_DtCvUnit percent;
_DtCvUnit slopUsed = 0;
_DtCvUnit slop = retWidth - cellWidth; /* the amount of room
required of the neighbors */
/*
* set the reformat flag
*/
if (False == retTabFlag)
reformat = True;
/*
* determine the maximum size the column can occupy
*/
for (j = 0, cellMax = 0;
j < thisCell->col_spn && j + myCol < max_cols; j++)
cellMax += col_specs[myCol+j].max;
/*
* determine the maximum available space from the neighbors.
*/
for (j = myCol + thisCell->col_spn, maxSlop = 0; j < max_cols; j++)
maxSlop = maxSlop + col_specs[j].actual - col_specs[j].min;
/*
* If the slop demanded is larger than available,
* simply reduced the other column specifications to their smallest
* values.
*/
if (slop >= maxSlop)
{
for (j = myCol + thisCell->col_spn; j < max_cols; j++)
col_specs[j].actual = col_specs[j].min;
/*
* Is it allowed for this column to 'hang over' the others?
*
* And is it the first one? I.e. don't allow more than one
* cell per row to overhang it's neighbors.
*
* And only allow it if the vertical text justification places
* the text at the top of the cell.
*/
if (_DtCvTRUE == col_specs[myCol].hanger
&& 0 == row_specs[row].y_adj
&& _DtCvJUSTIFY_TOP == TxtVertJustify(thisCell->cell_seg))
{
/*
* now set the other columns to start a little lower
* in their objects. Remove the bottom margin from the
* adjustment. One would hope that each of the containers
* for the columns in the row have the same bottom margin
* so that the overhung cell will push the next row down
* by the appropriate amount.
*/
row_specs[row].y_adj = retHeight -
_DtCvContainerBMarginOfSeg(thisCell->cell_seg);
row_specs[row].column = myCol;
retWidth = cellMax;
/*
* clear the reformat flag
*/
reformat = False;
}
}
else if (slop > 0)
{
/*
* the maximum slop available from the neighbors is
* enough. Now take space from my neighbors based
* on their orginal size. I.e. the larger they
* are, the more I take from them.
*/
for (j = myCol + thisCell->col_spn; j < max_cols; j++)
{
percent = col_specs[j].actual - col_specs[j].min;
value = slop * percent / maxSlop;
slopUsed += value;
col_specs[j].actual -= value;
}
/*
* if any more slop is needed, grab it on a strictly
* straight basis.
*/
do {
slop -= slopUsed;
for (j = myCol + thisCell->col_spn, slopUsed = 0;
slop > slopUsed && j < max_cols; j++)
{
if (col_specs[j].actual > col_specs[j].min)
{
col_specs[j].actual--;
slopUsed++;
}
}
} while (slopUsed > 0 && slop > slopUsed);
}
/*
* set the column width in the controlling column struct.
*/
if (thisCell->col_spn == 1)
{
col_specs[myCol].actual = retWidth;
}
else
{
/*
* how much to spread among the columns?
*/
slop = cellMax - retWidth;
/*
* if the aggragate max width is smaller than required,
* allocate the excess among the columns.
*/
if (slop < 0)
{
/*
* set the desired to the max and calculate the leftover
* slop and the maximum desired size.
*/
for (j = 0, slop = retWidth, maxSlop = 0;
myCol + j < max_cols && j < thisCell->col_spn; j++)
{
col_specs[j].actual = col_specs[myCol + j].max;
slop -= col_specs[myCol + j].max;
maxSlop += col_specs[myCol + j].max;
}
/*
* now allocate the leftover slop to each colum
* based on the maximum desired size.
*/
for (j = 0, slopUsed = 0;
slop > slopUsed && myCol + j < max_cols
&& j < thisCell->col_spn; j++)
{
value = slop * col_specs[myCol + j].max / maxSlop;
if (((slop*col_specs[myCol+j].max) % maxSlop) >= (maxSlop/2))
value++;
col_specs[myCol + j].actual += value;
slopUsed += value;
}
}
else if (slop > 0)
{
slopUsed = 0;
for (j = myCol;
j < max_cols && j < myCol + thisCell->col_spn; j++)
{
percent = col_specs[j].max - col_specs[j].actual;
value = slop * percent / maxSlop;
slopUsed += value;
col_specs[j].actual += value;
}
do {
slop -= slopUsed;
for (j = myCol, slopUsed = 0; slop > slopUsed &&
j < max_cols && j < myCol + thisCell->col_spn; j++)
{
if (col_specs[j].actual < col_specs[j].max)
{
col_specs[j].actual++;
slopUsed++;
}
}
} while (slopUsed > 0 && slop > slopUsed);
}
else /* if (slop == 0) */
{
for (j = 0; myCol + j < max_cols && j < thisCell->col_spn; j++)
col_specs[j].actual = col_specs[myCol + j].max;
}
}
}
return reformat;
}
/******************************************************************************
* Function: ProcessTable
*
*****************************************************************************/
static void
ProcessTable(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *table,
_DtCvUnit min_y)
{
int a;
int b;
int c;
int col;
int row;
int cell;
int divisor;
int maxCols;
int maxRows;
int maxRowSpn;
int saveLnStart = canvas->line_cnt;
int saveTxtStart = canvas->txt_cnt;
int saveTravCnt = canvas->trav_cnt;
_DtCvUnit workWidth;
_DtCvUnit newLeft;
_DtCvUnit saveLeft = layout->left;
_DtCvUnit saveYpos = layout->info.y_pos;
_DtCvUnit tableYpos;
_DtCvUnit newHeight;
_DtCvUnit newWidth;
_DtCvUnit oldAlignPos;
short anchorRow = -1;
const char **widthStr;
const char *saveAlignChar = layout->info.align_char;
char **rowIds;
char *alignCharacters = NULL;
char alignBuf[16];
_DtCvFrmtOption saveTxtJustify = layout->txt_justify;
_DtCvFrmtOption colJustify = _DtCvJUSTIFY_LEFT;
_DtCvFrmtOption *colJustSpec;
_DtCvValue oldFound = layout->id_found;
_DtCvValue haveBrds = False;
_DtCvValue saveState = layout->table_flag;
_DtCvValue saveAlignFlag = layout->info.align_flag;
_DtCvValue saveAlignPos = layout->info.align_pos;
_DtCvValue redo;
CellInfo defCell;
CellInfo *cellInfo = &defCell;
ColumnSpec defColumn;
ColumnSpec *colSpecs = &defColumn;
RowSpec defRow;
RowSpec *rowSpecs = &defRow;
DataPoint basePt;
GrpInfo grpInfo = DefGrpInfo;
/*
* get the base margins that the table will be working in.
*/
GetCurrentDataPoint(layout, &basePt);
/*
* find out how many rows there are.
*/
for (rowIds = _DtCvCellIdsOfTableSeg(table), maxRows = 0;
rowIds != NULL && rowIds[maxRows] != NULL; maxRows++);
if (maxRows == 0)
return;
/*
* get the number of columns and the column widths
*/
maxCols = _DtCvNumColsOfTableSeg(table);
widthStr = (const char **)_DtCvColWOfTableSeg(table);
colJustSpec = _DtCvColJustifyOfTableSeg(table);
if (maxCols < 1)
maxCols = 1;
if (widthStr == NULL)
widthStr = DefWidth;
/*
* determine the width the table has to work with.
*/
workWidth = layout->max_width - basePt.left - basePt.right -
layout->left - layout->right;
if (workWidth < 0)
workWidth = 0;
/*
* turn the string specifying column widths into units.
*/
if (maxCols != 1)
{
colSpecs = (ColumnSpec *) malloc (sizeof(ColumnSpec) * maxCols);
if (colSpecs == NULL)
return;
}
if (maxRows != 1)
{
rowSpecs = (RowSpec *) malloc (sizeof(RowSpec) * maxRows);
if (rowSpecs == NULL)
{
if (maxCols > 1)
free(colSpecs);
return;
}
}
if (maxRows != 1 || maxCols != 1)
{
cellInfo = (CellInfo *) malloc (sizeof(CellInfo) * maxCols * maxRows);
if (cellInfo == NULL)
{
if (maxCols > 1)
free(colSpecs);
if (maxRows > 1)
free(rowSpecs);
return;
}
}
/*
* for each column, process the width specification.
* '+Optimal,Take,Give'
*
* + - means the cell can 'hang over' its neighbors.
* It will take everything it can get and then
* push the other below it. (Labeled lists).
* Optimal - The desired percentage of the available space to
* use for the column.
* Take - The percentage amount the column will take from
* other columns to make itself 'fit'.
* Give - The percentage amount the column is willing to give up
* to other columns for them to 'fit'.
*/
for (col = 0, divisor = 0; col < maxCols; col++)
{
const char *nxtWidth = *widthStr;
/*
* move to the meat of the width specification string.
*/
SkipToNumber(&nxtWidth);
/*
* set the correct 'allow hangers' flag.
*/
colSpecs[col].hanger = _DtCvFALSE;
if ('+' == *nxtWidth)
{
colSpecs[col].hanger = _DtCvTRUE;
nxtWidth++;
}
/*
* now process the O,G,T specification.
*/
a = GetValueFromString(&nxtWidth, 1); if (a < 1) a = 1;
b = GetValueFromString(&nxtWidth, 0); if (b < 0) b = 0;
c = GetValueFromString(&nxtWidth, b); if (c > a) c = a;
/*
* for now just get the base percentages.
*/
colSpecs[col].min = a - c;
colSpecs[col].actual = a;
colSpecs[col].max = a + b;
/*
* get the column justification.
*/
if (NULL != colJustSpec)
{
colJustify = *colJustSpec;
colJustSpec++;
}
colSpecs[col].justify = colJustify;
if (_DtCvINHERIT == colJustify)
colSpecs[col].justify = saveTxtJustify;
/*
* up the divisor value.
*/
divisor += colSpecs[col].actual;
/*
* skip to the next set of width specifications
*/
if (col + 1 < maxCols && NULL != widthStr[1])
widthStr++;
/*
* initialize the cell information for the rows in this column
*/
for (row = 0; row < maxRows; row++)
{
cellInfo[row * maxCols + col].cell_seg = NULL;
cellInfo[row * maxCols + col].col_spn = 0;
cellInfo[row * maxCols + col].row_spn = 0;
cellInfo[row * maxCols + col].info = DefLayFrmtInfo;
}
}
/*
* initialize the row specs
*/
newHeight = 0;
if (-1 != min_y && 1 == maxRows)
newHeight = min_y - saveYpos;
for (row = 0; row < maxRows; row++)
{
rowSpecs[row].column = -1;
rowSpecs[row].y_adj = 0;
rowSpecs[row].height = newHeight;
rowSpecs[row].height = newHeight;
rowSpecs[row].next_id = rowIds[row];
}
/*
* now figure the real values
*/
if (divisor < 1)
divisor = 1;
for (col = 0; col < maxCols; col++)
{
colSpecs[col].min = workWidth * colSpecs[col].min / divisor;
colSpecs[col].actual = workWidth * colSpecs[col].actual / divisor;
colSpecs[col].max = workWidth * colSpecs[col].max / divisor;
if (colSpecs[col].min < 1)
colSpecs[col].min = 1;
if (colSpecs[col].actual < 1)
colSpecs[col].actual = 1;
if (colSpecs[col].max < 1)
colSpecs[col].max = 1;
}
/*
* now process the table.
*/
tableYpos = layout->info.y_pos;
maxRowSpn = 1;
alignCharacters = _DtCvJustifyCharsOfTableSeg(table);
/*
* set up the state of table processing and
* the beginning line/text counts.
*/
layout->table_flag = True;
SetBeginCounts(canvas, &(grpInfo.cnt));
/*
* now process each column, row by row.
* Doing it row by row allows the columns to shake out their
* sizing with less reformatting.
*/
for (col = 0; col < maxCols; col++)
{
/*
* remember where this column starts.
*/
saveTravCnt = canvas->trav_cnt;
saveLnStart = canvas->line_cnt;
saveTxtStart = canvas->txt_cnt;
newLeft = layout->left;
colJustify = layout->txt_justify;
layout->txt_justify = colSpecs[col].justify;
/*
* initialize the JUSTIFY_NUM or JUSTIFY_CHAR information
*/
layout->info.align_pos = 0;
layout->info.align_char = PeriodStr;
if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
{
/*
* are any alignment characters specified?
*/
if (NULL != alignCharacters && '\0' != *alignCharacters)
{
int len = mblen(alignCharacters, MB_CUR_MAX);
/*
* copy the character into a buffer
*/
strncpy(alignBuf, alignCharacters, len);
alignBuf[len] = '\0';
layout->info.align_char = alignBuf;
/*
* are there more characters? If so increment for the
* next column that may have JUSTIFY_CHAR. Otherwise,
* leave alone and re-use for other columns.
*/
if ('\0' != alignCharacters[len])
alignCharacters += len;
}
/* no...then default */
else
layout->txt_justify = _DtCvJUSTIFY_LEFT;
}
do {
/*
* reset the counts to the start
*/
canvas->trav_cnt = saveTravCnt;
canvas->line_cnt = saveLnStart;
canvas->txt_cnt = saveTxtStart;
layout->left = newLeft;
/*
* for each row, format the cell in this columns
*/
for (row = 0, redo = False, cell = col;
row < maxRows && redo == False;
row++, cell += maxCols)
{
/*
* remember the old height
*/
rowSpecs[row].lst_height = rowSpecs[row].height;
/*
* set the alignment flag for each column in the row.
*/
layout->info.align_flag = False;
if (_DtCvJUSTIFY_CHAR == layout->txt_justify ||
_DtCvJUSTIFY_NUM == layout->txt_justify)
layout->info.align_flag = True;
/*
* remember the alignment position
*/
oldAlignPos = layout->info.align_pos;
/*
* layout all the cells jammed to the top of the table.
* later, they get moved down to their position.
*/
layout->info.y_pos = tableYpos;
redo = ResolveCell(canvas, layout, table,
colSpecs, rowSpecs, col, row,
maxCols, maxRows, cellInfo);
/*
* check for maximum row span
*/
if (maxRowSpn < cellInfo[cell].row_spn)
maxRowSpn = cellInfo[cell].row_spn;
/*
* did the cell have borders?
*/
if (0 != cellInfo[cell].info.cnt.my_lines)
haveBrds = True;
/*
* check to see if the specified anchor has been found in
* this row. If so, save some information for later use.
*/
if (anchorRow == -1 && oldFound != layout->id_found)
anchorRow = row;
/*
* check to see if the alignment position has changed.
* for all but the first row!
*/
if (0 != row && oldAlignPos != layout->info.align_pos)
redo = True;
}
if (True == redo)
{
for (a = 0; a < row; a++)
{
/*
* restore the old row heights for this column
*/
rowSpecs[a].height = rowSpecs[a].lst_height;
/*
* reset the hanging cell information.
*/
if (col == rowSpecs[a].column)
{
rowSpecs[a].column = -1;
rowSpecs[a].y_adj = 0;
}
}
}
} while (redo == True);
/*
* push the next column to the right by size of this column
*/
layout->left += colSpecs[col].actual;
/*
* restore the horizontal text justification
*/
layout->txt_justify = colJustify;
}
/*
* set the ending counts for the lines/text in the table.
* and save the information as long as we are not a table
* that is a descendant of some container with a border and
* our cells include borders and we're going to have to honor
* boundaries.
*/
SetEndCounts(canvas, &(grpInfo.cnt), 0);
if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint &&
False == layout->brdr_flag && True == haveBrds)
{
GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
/*
* warning - nothing done if malloc error.
*/
if (NULL != info)
{
/*
* initialize to the line counts for the table
*/
*info = grpInfo;
/*
* set the linked list information
*/
info->next_info = layout->grp_lst;
layout->grp_lst = info;
}
}
/*
* Now go back and search for zeroed row heights and fill them in
* based on spanned rows. This can only happen if maxRowSpn is
* greater than 1! Otherwise, a row height really did end up zero!
*/
if (maxRowSpn > 1)
{
/*
* try to resolve the zero height rows
*/
for (a = 1, redo = True; redo && a < maxRowSpn; a++)
{
redo = False;
for (row = 0; row < maxRows; row++)
{
if (rowSpecs[row].height == 0 &&
ResolveHeight(rowSpecs, cellInfo, maxCols, row, a) == 0)
redo = True;
}
}
/*
* if any of the rows comes up unresolved, force to an average
* line height.
*
* But only do this if the first cell *does not* span all the rows
* and columns.
*/
if (redo &&
cellInfo[0].row_spn != maxRows && cellInfo[0].col_spn != maxCols)
{
for (row = 0; row < maxRows; row++)
{
if (rowSpecs[row].height == 0)
rowSpecs[row].height = canvas->metrics.line_height;
}
}
/*
* Now, double check that the row heights will accommodate
* all the cells.
*/
for (row = 0; row < maxRows; row++)
for (col = 0; col < maxCols; col++)
AdjustHeight(cellInfo, rowSpecs, maxCols, row, col);
}
/*
* now check that the minimum heights used for the rows matches
* or exceeds the minimum y position required.
*/
if (-1 != min_y)
{
_DtCvUnit pad;
for (newHeight = 0, row = 0; row < maxRows; row++)
newHeight += rowSpecs[row].height;
if (tableYpos + newHeight < min_y)
{
newHeight = tableYpos - min_y;
for (row = 0; 0 < newHeight && row < maxRows; row++)
{
pad = (newHeight/(maxRows-row));
rowSpecs[row].height += pad;
newHeight -= pad;
}
}
}
/*
* now reposition the cells based on the final row heights.
*/
layout->info.y_pos = tableYpos;
for (tableYpos = 0, cell = 0, row = 0; row < maxRows;
tableYpos = tableYpos + rowSpecs[row].height + rowSpecs[row].y_adj,
row++)
{
/*
* check to see if the specified anchor has been found in this
* row. If so, adjust the found position.
*/
if (anchorRow == row)
layout->id_Ypos += tableYpos;
for (col = 0, layout->left = saveLeft; col < maxCols;
layout->left += colSpecs[col++].actual, cell++)
{
if (cellInfo[cell].cell_seg != NULL)
{
/*
* calculate the new height
*/
for (newHeight = 0, a = 0; a < cellInfo[cell].row_spn; a++)
{
newHeight += rowSpecs[row + a].height;
if (col != rowSpecs[row + a].column)
newHeight += rowSpecs[row + a].y_adj;
}
/*
* calculate the new width.
*/
for (newWidth = 0, a = 0; a < cellInfo[cell].col_spn; a++)
newWidth += colSpecs[col + a].actual;
/*
* now get the overhang space for this cell
*/
workWidth = 0;
if (col > rowSpecs[row].column)
workWidth = rowSpecs[row].y_adj;
/*
* if the heights (and/or width for spanning columns)
* are different, check to see if the
* cell contains lines that may be affected by the
* height adjustment.
*
* It is strongly assumed that if a table specifies that
* a cell can hang over it's neighbors that it will *NOT*
* have borders (whereby LinesMayChange is false) and
* newWidth will not be greater than the cell's width.
*/
if ((newHeight > cellInfo[cell].info.height &&
True == LinesMayChange(canvas,
cellInfo[cell].info.cnt.beg_ln,
cellInfo[cell].info.cnt.end_ln,
cellInfo[cell].info.cnt.my_lines))
||
(1 < cellInfo[cell].col_spn &&
newWidth > cellInfo[cell].info.width))
ReFormatCell(canvas, layout, &cellInfo[cell], colSpecs,
col, newHeight,
layout->info.y_pos + tableYpos);
else
/* adjust the cell rather than reformatting */
AdjustObjectPosition(canvas, layout,
TxtVertJustify(cellInfo[cell].cell_seg),
cellInfo[cell].info.cnt.beg_txt ,
cellInfo[cell].info.cnt.beg_ln ,
cellInfo[cell].info.cnt.beg_brk ,
cellInfo[cell].info.cnt.end_txt ,
cellInfo[cell].info.cnt.end_ln ,
cellInfo[cell].info.cnt.end_brk ,
cellInfo[cell].info.cnt.my_lines,
newHeight - cellInfo[cell].info.height,
0,
tableYpos, workWidth);
}
}
}
/*
* increment the maximum y.
*/
layout->info.y_pos += tableYpos;
layout->left = saveLeft;
if (maxCols > 1)
free(colSpecs);
if (maxRows > 1)
free(rowSpecs);
if (maxRows > 1 || maxCols > 1)
free(cellInfo);
layout->txt_justify = saveTxtJustify;
layout->table_flag = saveState;
/*
* restore the alignment information
*/
layout->info.align_flag = saveAlignFlag;
layout->info.align_char = saveAlignChar;
layout->info.align_pos = saveAlignPos;
}
/******************************************************************************
* Function: UpdateDimensionArrays
*
* Purpose: Based on the object's orientation and justification,
* update the correct dimension array(s).
*
*****************************************************************************/
static void
UpdateDimensionArrays(
_DtCvSegmentI *p_seg,
_DtCvUnit width,
_DtCvUnit height,
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow,
_DtCvUnit *max_left,
_DtCvUnit *max_right)
{
int i;
int j;
int *marginPtr;
_DtCvFrmtOption orient = ObjHorizOrient(p_seg);
_DtCvFrmtOption vOrient = ObjVertOrient(p_seg);
/*
* modify the width that headSize should be
*/
j = DIMS_LM;
i = DIMS_TOP;
switch (orient)
{
case _DtCvJUSTIFY_RIGHT_MARGIN:
j++;
case _DtCvJUSTIFY_CENTER:
j++;
case _DtCvJUSTIFY_LEFT_MARGIN:
if (vOrient == _DtCvJUSTIFY_BOTTOM)
i = DIMS_BOTTOM;
if ((*top_bot)[i][j][DIMS_WIDTH] < width)
(*top_bot)[i][j][DIMS_WIDTH] = width;
if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(p_seg))
(*top_bot)[i][j][DIMS_HEIGHT] += height;
break;
}
/*
* check left & right margins.
*/
marginPtr = max_left;
j = DIMS_LEFT;
i = DIMS_TOP;
switch(orient)
{
case _DtCvJUSTIFY_RIGHT_CORNER:
case _DtCvJUSTIFY_RIGHT:
j = DIMS_RIGHT;
marginPtr = max_right;
case _DtCvJUSTIFY_LEFT_CORNER:
case _DtCvJUSTIFY_LEFT:
if (vOrient != _DtCvJUSTIFY_TOP)
i++;
if (vOrient == _DtCvJUSTIFY_BOTTOM)
i++;
/*
* push i to zero or 4
*/
if (orient == _DtCvJUSTIFY_RIGHT_CORNER ||
orient == _DtCvJUSTIFY_LEFT_CORNER)
{
if (i) i = DIMS_BC;
(*corner)[i][j] += height;
if (*marginPtr < width)
*marginPtr = width;
}
else if (_DtCvContainerFlowOfSeg(p_seg) != _DtCvWRAP)
{
(*side)[i][j] += height;
if (*marginPtr < width)
*marginPtr = width;
}
else
{
(*flow)[j][DIMS_HEIGHT] += height;
if ((*flow)[j][DIMS_WIDTH] < width)
(*flow)[j][DIMS_WIDTH] = width;
}
break;
}
}
/******************************************************************************
* Function: DetermineMaxDims
*
*****************************************************************************/
static void
DetermineMaxDims(
TopDims *top_bot,
CornerDims *corner,
_DtCvUnit left_margin,
_DtCvUnit right_margin,
_DtCvUnit *top_height,
_DtCvUnit *bot_height,
_DtCvUnit *max_width)
{
int j;
_DtCvUnit topWidth;
_DtCvUnit botWidth;
/*
* now process all the information gathered about the (sub)headings
* to determine the bounding box for the (head) txt. Start by figuring
* out the maximums for the dimensions.
*
* figure the current top and bottom max widths.
*/
topWidth = left_margin + right_margin;
botWidth = left_margin + right_margin;
*top_height = 0;
*bot_height = 0;
for (j = DIMS_LM; j <= DIMS_RM; j++)
{
topWidth = topWidth + (*top_bot)[DIMS_TOP] [j][DIMS_WIDTH];
botWidth = botWidth + (*top_bot)[DIMS_BOTTOM][j][DIMS_WIDTH];
if (*top_height < (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT])
*top_height = (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT];
if (*bot_height < (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT])
*bot_height = (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT];
}
/*
* for the maximum top and bottom heights, take into
* consideration the corner values
*/
if (*top_height < (*corner)[DIMS_TC][DIMS_LEFT])
*top_height = (*corner)[DIMS_TC][DIMS_LEFT];
if (*top_height < (*corner)[DIMS_TC][DIMS_RIGHT])
*top_height = (*corner)[DIMS_TC][DIMS_RIGHT];
if (*bot_height < (*corner)[DIMS_BC][DIMS_LEFT])
*bot_height = (*corner)[DIMS_BC][DIMS_LEFT];
if (*bot_height < (*corner)[DIMS_BC][DIMS_RIGHT])
*bot_height = (*corner)[DIMS_BC][DIMS_RIGHT];
*max_width = topWidth;
if (*max_width < botWidth)
*max_width = botWidth;
}
/******************************************************************************
* Function: DetermineFlowConstraints
*
*****************************************************************************/
static void
DetermineFlowConstraints(
LayoutInfo *layout,
FlowDims flow_dims,
_DtCvUnit left_margin,
_DtCvUnit right_margin,
_DtCvUnit start_y,
DataPoint *left_pt,
DataPoint *right_pt)
{
_DtCvUnit leftSide = flow_dims[DIMS_LEFT][DIMS_HEIGHT];
_DtCvUnit rightSide = flow_dims[DIMS_RIGHT][DIMS_HEIGHT];
/*
* Now, if there is flowing text required, put points on the
* stack to indicate them.
*/
left_margin += flow_dims[DIMS_LEFT][DIMS_WIDTH];
right_margin += flow_dims[DIMS_RIGHT][DIMS_WIDTH];
GetCurrentDataPoint(layout, left_pt);
GetCurrentDataPoint(layout, right_pt);
left_pt->left += left_margin;
left_pt->right += right_margin;
left_pt->y_pos = _CEFORMAT_ALL;
right_pt->left += left_margin;
right_pt->right += right_margin;
right_pt->y_pos = _CEFORMAT_ALL;
while (leftSide > 0 || rightSide > 0)
{
if (leftSide > 0)
{
if (rightSide == 0 || leftSide <= rightSide)
{
left_pt->right = right_margin;
left_pt->y_pos = start_y + leftSide;
if (leftSide != rightSide)
left_margin = 0;
leftSide = 0;
InsertDataPoint(layout, left_pt);
}
}
if (rightSide > 0)
{
if (leftSide == 0 || leftSide > rightSide)
{
right_pt->left = left_margin;
right_pt->y_pos = start_y + rightSide;
if (leftSide != rightSide)
right_margin = 0;
rightSide = 0;
InsertDataPoint(layout, right_pt);
}
}
}
}
/******************************************************************************
* Function: DetermineHeadPositioning
*
*****************************************************************************/
static void
DetermineHeadPositioning(
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow,
_DtCvUnit start_y,
_DtCvUnit max_top,
_DtCvUnit block_size,
_DtCvUnit *ret_side_size)
{
int i;
_DtCvUnit leftSideHeight = 0;
_DtCvUnit rightSideHeight = 0;
_DtCvUnit sideHeight = 0;
/*
* determine the maximum side heights
*/
for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
{
leftSideHeight += (*side)[i][DIMS_LEFT];
rightSideHeight += (*side)[i][DIMS_RIGHT];
}
/*
* determine the maximum side height
*/
sideHeight = block_size;
if (sideHeight < leftSideHeight)
sideHeight = leftSideHeight;
if (sideHeight < rightSideHeight)
sideHeight = rightSideHeight;
if (sideHeight < (*flow)[DIMS_LEFT][DIMS_HEIGHT])
sideHeight = (*flow)[DIMS_LEFT][DIMS_HEIGHT];
if (sideHeight < (*flow)[DIMS_RIGHT][DIMS_HEIGHT])
sideHeight = (*flow)[DIMS_RIGHT][DIMS_HEIGHT];
/*
* calculate the starting Y position for each of the positions
* reuse the arrays that were used to save the max dimension values.
*/
for (i = DIMS_LM; i <= DIMS_RM; i++)
{
(*top_bot)[DIMS_TOP] [i][DIMS_YPOS] = start_y;
(*top_bot)[DIMS_BOTTOM][i][DIMS_YPOS] = start_y + max_top + sideHeight;
}
(*corner)[DIMS_TC][DIMS_LEFT] = start_y;
(*corner)[DIMS_TC][DIMS_RIGHT] = start_y;
(*corner)[DIMS_BC][DIMS_LEFT] = start_y + max_top + sideHeight;
(*corner)[DIMS_BC][DIMS_RIGHT] = start_y + max_top + sideHeight;
(*side)[DIMS_TOP][DIMS_LEFT] = start_y + max_top;
(*side)[DIMS_TOP][DIMS_RIGHT] = start_y + max_top;
(*flow)[DIMS_LEFT ][DIMS_YPOS] = start_y + max_top;
(*flow)[DIMS_RIGHT][DIMS_YPOS] = start_y + max_top;
(*side)[DIMS_CENTER][DIMS_LEFT] = start_y + max_top +
(sideHeight - (*side)[DIMS_CENTER][DIMS_LEFT]) / 2;
(*side)[DIMS_CENTER][DIMS_RIGHT] = start_y + max_top +
(sideHeight - (*side)[DIMS_CENTER][DIMS_RIGHT]) / 2;
(*side)[DIMS_BOTTOM][DIMS_LEFT] = start_y + max_top +
sideHeight - (*side)[DIMS_BOTTOM][DIMS_LEFT];
(*side)[DIMS_BOTTOM][DIMS_RIGHT] = start_y + max_top +
sideHeight - (*side)[DIMS_BOTTOM][DIMS_RIGHT];
if (ret_side_size != NULL)
*ret_side_size = sideHeight;
}
/******************************************************************************
* Function: AdjustHead
*
* Parameters:
* base_left Specifies the x position that the controller
* occupying 'left_margin' space would start
* at.
* block_width Specifies the body's width for which to
* center or align a controller with.
* left_margin Specifies the space used by a controller
* that is on the left side of the body.
* right_margin Specifies the space used by a controller
* on the right side of the body.
*
*****************************************************************************/
static void
AdjustHeadPosition(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *p_seg,
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow,
LayFrmtInfo *info,
_DtCvUnit base_y,
_DtCvUnit base_left,
_DtCvUnit block_width,
_DtCvUnit left_margin,
_DtCvUnit right_margin)
{
int i = DIMS_TOP; /* also DIMS_TC */
int j = DIMS_LEFT; /* also DIMS_LM */
int divisor = 2;
_DtCvUnit adjustX = 0;
_DtCvUnit adjustY = 0;
_DtCvUnit newY = 0;
_DtCvUnit headWidth = info->width;
_DtCvFrmtOption orient = ObjHorizOrient(p_seg);
_DtCvFrmtOption vOrient = ObjVertOrient(p_seg);
if (_DtCvContainerPercentOfSeg(p_seg) == 10000
&& orient == _DtCvJUSTIFY_CENTER
&& TxtHorizJustify(p_seg) == _DtCvJUSTIFY_LEFT)
headWidth = block_width;
switch (orient)
{
case _DtCvJUSTIFY_RIGHT_MARGIN:
divisor = 1;
j++;
case _DtCvJUSTIFY_CENTER:
adjustX = (block_width - headWidth) / divisor;
j++;
case _DtCvJUSTIFY_LEFT_MARGIN:
adjustX += left_margin;
if (vOrient == _DtCvJUSTIFY_BOTTOM)
i = DIMS_BOTTOM;
newY = (*top_bot)[i][j][DIMS_YPOS];
(*top_bot)[i][j][DIMS_YPOS] += info->height;
break;
case _DtCvJUSTIFY_RIGHT_CORNER:
adjustX = block_width + left_margin;
j = DIMS_RIGHT;
case _DtCvJUSTIFY_LEFT_CORNER:
if (vOrient == _DtCvJUSTIFY_BOTTOM)
i = DIMS_BC;
newY = (*corner)[i][j];
(*corner)[i][j] += info->height;
break;
case _DtCvJUSTIFY_RIGHT:
adjustX = block_width + left_margin;
j = DIMS_RIGHT;
case _DtCvJUSTIFY_LEFT:
if (vOrient != _DtCvJUSTIFY_TOP)
i++;
if (vOrient == _DtCvJUSTIFY_BOTTOM)
i++;
if (_DtCvContainerFlowOfSeg(p_seg) == _DtCvWRAP)
{
if (orient == _DtCvJUSTIFY_LEFT)
adjustX += left_margin;
else
adjustX -= headWidth;
newY = (*flow)[j][DIMS_YPOS];
(*flow)[j][DIMS_YPOS] += info->height;
}
else
{
newY = (*side)[i][j];
(*side)[i][j] += info->height;
}
break;
}
adjustY = newY - base_y;
adjustX += base_left;
/*
* adjust the text positions
*/
AdjustTextPositions(canvas, info->cnt.beg_txt, info->cnt.end_txt,
adjustX, adjustY);
/*
* adjust the lines positions
*/
AdjustLinePositions(canvas, info->cnt.beg_ln, info->cnt.end_ln,
adjustX, adjustY);
/*
* adjust the page breaks, but only if necessary.
*/
AdjustPgBrk(canvas, info->cnt.beg_brk, info->cnt.end_brk, adjustY);
}
/******************************************************************************
* Function: InitDimArrays
*
*****************************************************************************/
static void
InitDimArrays(
TopDims *top_bot,
SideDims *side,
CornerDims *corner,
FlowDims *flow)
{
int i;
int j;
for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
{
for (j = DIMS_LM; j <= DIMS_RM; j++)
{
(*top_bot)[i][j][DIMS_WIDTH] = 0;
(*top_bot)[i][j][DIMS_HEIGHT] = 0;
}
for (j = DIMS_LEFT; j <= DIMS_RIGHT; j++)
(*side)[i][j] = 0;
}
for (i = DIMS_LEFT; i <= DIMS_RIGHT; i++)
{
for (j = DIMS_WIDTH; j <= DIMS_HEIGHT; j++)
{
(*corner)[i][j] = 0;
(*flow)[i][j] = 0;
}
}
}
/******************************************************************************
* Function: ProcessController
*****************************************************************************/
static LayFrmtInfo *
ProcessController(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cur_seg)
{
int getLn;
int saveTravCnt = canvas->trav_cnt;
_DtCvUnit saveYPos = layout->info.y_pos;
_DtCvUnit saveMaxWidth = layout->max_width;
_DtCvUnit saveLeft = layout->left;
_DtCvUnit saveRight = layout->right;
_DtCvUnit maxWidth;
_DtCvUnit maxXPos;
_DtCvUnit myMaxWidth;
LayFrmtInfo *frmtInfo;
DataPoint basePt;
DataPoint zeroPt;
_DtCvValue redo;
/*
* Controllers always break the formatting sequence.
* So save any information in the buffer, reset the margins and
* add the appropriate lines, and check for going over boundaries.
*/
CheckSaveInfo(canvas, layout, cur_seg, 0);
CheckFormat(layout, True);
/*
* Get the controller specific information.
* disallow some of the orientation & vOrient combinations
*/
if ((ObjHorizOrient(cur_seg) == _DtCvJUSTIFY_CENTER
&& ObjVertOrient(cur_seg) != _DtCvJUSTIFY_BOTTOM)
||
(ObjVertOrient(cur_seg) == _DtCvJUSTIFY_CENTER
&& ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
&& ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT))
ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP
&&
(ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
||
(ObjVertOrient(cur_seg) == _DtCvJUSTIFY_TOP
&& ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
&& ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT)))
_DtCvContainerFlowOfSeg(cur_seg) = _DtCvWRAP_NONE;
if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP_JOIN
&&
(ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
|| ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT_MARGIN))
{
ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
ObjHorizOrient(cur_seg) = _DtCvJUSTIFY_LEFT_MARGIN;
}
/*
* malloc a formatting dimension structure and initialize it with
* default values. This will be returned to the caller.
*/
frmtInfo = (LayFrmtInfo *) malloc (sizeof(LayFrmtInfo));
*frmtInfo = DefLayFrmtInfo;
/*
* the controller object begins here.
*/
SetBeginCounts(canvas, &(frmtInfo->cnt));
/*
* set the parent's data point in the stack
*/
GetCurrentDataPoint(layout, &basePt);
/*
* calculate the amount of space the controller can occupy.
* first calculate the amount of space to work with.
* then truncate to zero if necessary.
* then use the percentage of that remaining area as the space
* the controller's segments can occupy.
*/
myMaxWidth = layout->max_width - basePt.left - basePt.right
- saveLeft - saveRight;
if (myMaxWidth < 0)
myMaxWidth = 0;
myMaxWidth = (_DtCvUnit) (((double) myMaxWidth)
* ((double) _DtCvContainerPercentOfSeg(cur_seg))
/ HeadDivisor);
/*
* Format the controller at a 'zero'ed point.
* The lines it generates will be moved later to their correct position.
*/
layout->left = 0;
layout->right = 0;
zeroPt = DefDataPt;
PushDataPoint(layout, &zeroPt);
/*
* now process as a regular container
*/
do {
/*
* set some counts and flags (necessary for a redo).
*/
redo = False;
canvas->trav_cnt = saveTravCnt;
canvas->line_cnt = frmtInfo->cnt.beg_ln;
canvas->txt_cnt = frmtInfo->cnt.beg_txt;
layout->max_width = myMaxWidth;
layout->info.y_pos = 0;
/*
* process the container
*/
ProcessContainer(canvas,layout,cur_seg,-1,&maxWidth,&maxXPos,&getLn);
/*
* check to see if we need to reformat because the minimum size
* is larger than we asked for.
*/
if (maxXPos + _DtCvContainerRMarginOfSeg(cur_seg) > myMaxWidth)
{
redo = True;
myMaxWidth = maxXPos + _DtCvContainerRMarginOfSeg(cur_seg);
}
} while (True == redo);
/*
* remove this element's data points from the stack.
*/
RemoveDataPoint(layout, &zeroPt);
/*
* set the ending counts for the items in this container.
*/
SetEndCounts(canvas, &(frmtInfo->cnt), getLn);
frmtInfo->width = myMaxWidth;
frmtInfo->height = layout->info.y_pos;
/*
* does this controller want to join with the lines in a non-controller?
*/
if (_DtCvWRAP_JOIN == _DtCvContainerFlowOfSeg(cur_seg)
&& frmtInfo->cnt.beg_txt != canvas->txt_cnt)
_DtCvSetJoinInfo(&(layout->info), True, canvas->txt_cnt - 1);
/*
* Restore the previous information
*/
if (NULL != layout->lst_rendered)
layout->lst_rendered->next_disp = NULL;
layout->left = saveLeft;
layout->right = saveRight;
layout->max_width = saveMaxWidth;
layout->lst_rendered = NULL;
layout->info.y_pos = saveYPos;
return frmtInfo;
}
/******************************************************************************
* Function: AdjustForBorders
*
* Initializes the display line and graphic tables.
*****************************************************************************/
static void
AdjustForBorders(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption brdr,
_DtCvUnit line_width,
_DtCvUnit *ret_bot,
_DtCvUnit *ret_right)
{
/*
* if the line_width is zero, make it 1 so that is really takes
* up some space.
*/
if (0 == line_width)
line_width = 1;
/*
* set the flag for processing a border
*/
if (_DtCvBORDER_NONE != brdr)
layout->brdr_flag = True;
/*
* check to see if this element has a border. If so, adjust the
* boundaries.
*/
if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
|| brdr == _DtCvBORDER_TOP
|| brdr == _DtCvBORDER_TOP_LEFT
|| brdr == _DtCvBORDER_TOP_RIGHT)
layout->info.y_pos += line_width;
*ret_bot = 0;
if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
|| brdr == _DtCvBORDER_BOTTOM
|| brdr == _DtCvBORDER_BOTTOM_LEFT
|| brdr == _DtCvBORDER_BOTTOM_RIGHT)
*ret_bot = line_width;
if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
|| brdr == _DtCvBORDER_LEFT
|| brdr == _DtCvBORDER_TOP_LEFT
|| brdr == _DtCvBORDER_BOTTOM_LEFT)
layout->left += line_width;
*ret_right = 0;
if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
|| brdr == _DtCvBORDER_RIGHT
|| brdr == _DtCvBORDER_TOP_RIGHT
|| brdr == _DtCvBORDER_BOTTOM_RIGHT)
{
layout->right += line_width;
*ret_right = line_width;
}
}
/******************************************************************************
* Function: DrawBorders
*
* Parameters:
* canvas Specifies the virtual canvas on which
* lines are drawn.
* layout Specifies the current layout information.
* brdr Specifies the type of border.
* top_y Specifes the top y of the bounding box for
* the object. Any border drawn should be
* completely below this y.
* bot_y Specifes the bottom y of the bounding box
* for the object. Any border drawn should be
* completely below this y.
* left_x Specifies the left x of the bounding box
* for the object. Any border drawn should be
* completely to the right of this x.
* right_x Specifies the right x of the bounding box
* for the object. Any border drawn should be
* completely to the left of this x.
*
* left_x right_x
* | |
* v v
* top_y ---> xxxxxxxxxxxxxxxxxxxxxx
* xxxxxxxxxxxxxxxxxxxxxx
* xx------------------xx
* xx| |xx (xx represents the line.)
* xx| |xx
* xx| |xx
* xx| |xx
* xx------------------xx
* bot_y ---> xxxxxxxxxxxxxxxxxxxxxx
* xxxxxxxxxxxxxxxxxxxxxx
*
*****************************************************************************/
static int
DrawBorders(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption brdr,
_DtCvPointer data,
_DtCvUnit line_width,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit left_x,
_DtCvUnit right_x)
{
int mod = 1;
int cnt = canvas->line_cnt;
_DtCvUnit width;
/*
* if line_width is zero, make it 1 so that it really takes
* up some space.
*/
if (0 == line_width)
line_width = 1;
/*
* calculate the width of the element.
*/
width = right_x - left_x;
/*
* If borders are specified, draw them
*/
if (brdr != _DtCvBORDER_NONE)
{
/*
* now do the horizontal borders. the coordinates are the top,
* left most unit of the line.
*/
switch(brdr)
{
case _DtCvBORDER_FULL:
case _DtCvBORDER_HORZ:
case _DtCvBORDER_BOTTOM:
case _DtCvBORDER_BOTTOM_LEFT:
case _DtCvBORDER_BOTTOM_RIGHT:
SaveLine(canvas, layout, _DtCvLINE_HORZ,
data, line_width,
left_x, bot_y, width);
mod = -1;
if (brdr == _DtCvBORDER_BOTTOM
|| brdr == _DtCvBORDER_BOTTOM_LEFT
|| brdr == _DtCvBORDER_BOTTOM_RIGHT)
break;
case _DtCvBORDER_TOP:
case _DtCvBORDER_TOP_LEFT:
case _DtCvBORDER_TOP_RIGHT:
SaveLine(canvas, layout, _DtCvLINE_HORZ,
data, line_width,
left_x, top_y, width);
}
/*
* for vertical lines, the coordinates are the top, right most
* unit of the line.
*/
switch(brdr)
{
case _DtCvBORDER_FULL:
case _DtCvBORDER_BOTTOM_LEFT:
/*
* include the line width in length for a full
* border.
*/
bot_y += line_width;
case _DtCvBORDER_VERT:
case _DtCvBORDER_LEFT:
case _DtCvBORDER_TOP_LEFT:
SaveLine(canvas, layout, _DtCvLINE_VERT,
data, line_width,
left_x, top_y, bot_y - top_y);
if (brdr == _DtCvBORDER_LEFT
|| brdr == _DtCvBORDER_TOP_LEFT
|| brdr == _DtCvBORDER_BOTTOM_LEFT)
break;
case _DtCvBORDER_BOTTOM_RIGHT:
/*
* if we didn't fall thru from above, we need to
* add the extension to the bottom to get the
* full length for the right vertical line.
*/
if (brdr == _DtCvBORDER_BOTTOM_RIGHT)
bot_y += line_width;
case _DtCvBORDER_RIGHT:
case _DtCvBORDER_TOP_RIGHT:
SaveLine(canvas, layout, _DtCvLINE_VERT,
data, line_width,
right_x - line_width, top_y, bot_y - top_y);
}
}
return ((canvas->line_cnt - cnt) * mod);
}
/******************************************************************************
* Function: AdjustObjectPosition
*
* Parameters:
* canvas Specifies the virtual canvas on which
* lines are drawn.
* justify Specifies the vertical adjustment for the
* object.
* start_txt Specifies the start index of the text list.
* start_gr Specifies the start index of the graphics list.
* start_ln Specifies the start index of the line list.
* end_txt Specifies the end indext of the text list.
* end_gr Specifies the end indext of the graphics list.
* end_ln Specifies the end indext of the line list.
* height_adj Specifies the internal height adjust value.
* Depending on the justify type, this may
* add to y_adj for text and regions, bottom
* lines and the height of vertical lines.
* y_adj Specifies the y position adjustment.
* Lines, text and regions are moved this
* amount.
* internal_y Specifies the internal y position adjustment.
* height_adj includes this value. Text and
* regions are moved this amount.
*
* Return: nothing.
*
*****************************************************************************/
static void
AdjustObjectPosition(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvFrmtOption justify,
int start_txt,
int start_ln,
int start_brk,
int end_txt,
int end_ln,
int end_brk,
int brdr_cnt,
_DtCvUnit height_adj,
_DtCvUnit x_adj,
_DtCvUnit y_adj,
_DtCvUnit internal_y)
{
int mod = 1;
_DtCvUnit yOff = 0;
/*
* If border count is negative, indicates the first line in the
* list is bottom line. This requires special handling in adjusting
* its position. Set flags accordingly.
*/
if (brdr_cnt < 0)
{
mod = -1;
brdr_cnt = -brdr_cnt;
}
/*
* calculate the offset value within the object for other objects
* contained in this object.
*/
if (justify != _DtCvJUSTIFY_TOP)
{
yOff = height_adj - internal_y;
if (justify == _DtCvJUSTIFY_CENTER)
yOff /= 2;
}
yOff += y_adj;
yOff += internal_y;
/*
* don't modify the border lines around this object yet.
*/
end_ln -= brdr_cnt;
/*
* modify the border lines of the objects contained within
* this object.
*/
AdjustLinePositions(canvas, start_ln, end_ln, x_adj, yOff);
/*
* now adjust the border lines around this object.
*/
start_ln = end_ln;
end_ln += brdr_cnt;
AdjustLinePositions(canvas, start_ln, end_ln, x_adj, y_adj);
/*
* now fix the lines if they've changed height and move
* the first line to its bottom position if necessary.
*/
if (0 != height_adj)
{
while (start_ln < end_ln)
{
/*
* indicates the bottom line is the first line in the
* list. Move it down the height adjustment.
*/
if (mod < 0)
{
canvas->line_lst[start_ln].pos_y += height_adj;
canvas->line_lst[start_ln].max_y += height_adj;
mod = 1;
}
/*
* stretch the vertical lines
*/
else if (canvas->line_lst[start_ln].dir == _DtCvLINE_VERT)
canvas->line_lst[start_ln].max_y += height_adj;
start_ln++;
}
}
/*
* adjust the position of the text within this object.
*/
AdjustTextPositions (canvas, start_txt, end_txt, x_adj, yOff);
/*
* adjust the position of the text within this object.
*/
AdjustPgBrk (canvas, start_brk, end_brk, yOff);
}
/******************************************************************************
* Function: LinesMayChange
*
* Parameters:
* canvas Specifies the virtual canvas on which
* lines are drawn.
* start_ln Specifies the start index of the line list.
* end_ln Specifies the end indext of the line list.
*
* Return: True if there is a vertical line as a child of a container.
* False if there are no vertical lines in the child of a
* container/cell.
*
*****************************************************************************/
static _DtCvValue
LinesMayChange(
_DtCanvasStruct *canvas,
int start_ln,
int end_ln,
int brdr_cnt)
{
/*
* If border count is negative, indicates that one of the lines
* is for the bottom of the container/cell. Ignore for now.
* we want to check the lines in the container/cell.
*/
if (brdr_cnt < 0)
brdr_cnt = -brdr_cnt;
/*
* get rid of the line count for this object,
* AdjustObjectPosition can take care of it.
*/
end_ln -= brdr_cnt;
/*
* Now check for vertical lines that would
* be affected by a height change.
*/
while (start_ln < end_ln)
{
if (_DtCvLINE_VERT == canvas->line_lst[start_ln].dir)
return True;
start_ln++;
}
return False;
}
/******************************************************************************
* Function: ProcessContainer
*
* Initializes the display line and graphic tables.
*****************************************************************************/
static void
ProcessContainer(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *con_seg,
_DtCvUnit min_y,
_DtCvUnit *ret_width,
_DtCvUnit *ret_max_x,
int *ret_cnt)
{
int getLn;
const char *saveJustifyChar = layout->info.align_char;
_DtCvUnit yPad = 0;
_DtCvUnit xPad = 0;
_DtCvUnit maxWidth = 0;
_DtCvUnit maxXPos = 0;
_DtCvUnit myMinY = -1;
_DtCvUnit saveLeft = layout->left;
_DtCvUnit saveRight = layout->right;
_DtCvUnit saveLead = layout->info.leading;
_DtCvUnit saveFirst = layout->first;
_DtCvUnit saveYpos = layout->info.y_pos;
_DtCvValue saveStatic = layout->stat_flag;
_DtCvValue saveBrdr = layout->brdr_flag;
_DtCvFrmtOption saveJustify = layout->txt_justify;
LayFrmtInfo frmtInfo;
DataPoint basePt;
DataPoint curPt;
/*
* check to see if this element breaks the formatting sequence.
* If so save any information in the buffer, reset the margins and
* add the appropriate lines, and check for going over boundaries.
*/
if (NotJoining(layout))
{
CheckSaveInfo(canvas, layout, con_seg, 0);
CheckFormat(layout, True);
}
/*
* check to see if this segment is the segment we want as our first
* visible line.
*/
CheckId(layout, _DtCvContainerIdOfSeg(con_seg));
/*
* Set beginning text and line counts
*/
frmtInfo = DefLayFrmtInfo;
SetBeginCounts(canvas, &(frmtInfo.cnt));
/*
* Get the first indent and set the current container pointer to me.
*/
layout->first = _DtCvContainerFMarginOfSeg(con_seg) / layout->divisor;
layout->left = _DtCvContainerLMarginOfSeg(con_seg) / layout->divisor;
layout->right = _DtCvContainerRMarginOfSeg(con_seg) / layout->divisor;
layout->info.leading = _DtCvContainerLeadingOfSeg(con_seg);
/*
* check to see if we violate the horiz_pad_hint on the left, right or
* first margins.
*/
if (canvas->metrics.horiz_pad_hint > _DtCvContainerLMarginOfSeg(con_seg))
layout->left = _DtCvContainerLMarginOfSeg(con_seg);
else if (layout->left < canvas->metrics.horiz_pad_hint)
layout->left = canvas->metrics.horiz_pad_hint;
if (canvas->metrics.horiz_pad_hint > _DtCvContainerRMarginOfSeg(con_seg))
layout->right = _DtCvContainerRMarginOfSeg(con_seg);
else if (layout->right < canvas->metrics.horiz_pad_hint)
layout->right = canvas->metrics.horiz_pad_hint;
if (canvas->metrics.horiz_pad_hint > _DtCvContainerFMarginOfSeg(con_seg))
layout->first = _DtCvContainerFMarginOfSeg(con_seg);
else if (layout->first < canvas->metrics.horiz_pad_hint)
layout->first = canvas->metrics.horiz_pad_hint;
/*
* check to see if there is more squeeze room available.
*/
if (layout->left > canvas->metrics.horiz_pad_hint
|| layout->right > canvas->metrics.horiz_pad_hint
|| layout->first > canvas->metrics.horiz_pad_hint)
layout->margin_non_zero = True;
/*
* set the formatting type for this container
*/
layout->stat_flag = False;
if (_DtCvContainerTypeOfSeg(con_seg) == _DtCvLITERAL)
layout->stat_flag = True;
/*
* check to see if this element breaks the formatting sequence.
* If so, add lines, etc.
*/
if (NotJoining(layout))
{
/*
* Adjust margins and y position for bordering
*/
AdjustForBorders (canvas, layout, Border(con_seg), BrdWidth(con_seg),
&yPad, &xPad);
_DtCvAddSpace(_DtCvContainerTMarginOfSeg(con_seg),
&(layout->info.y_pos));
/*
* check for flow limits.
*/
CheckFormat(layout, True);
/*
* get the parent's data point in the stack
* and add the current container's left and right to it.
*/
GetCurrentDataPoint(layout, &basePt);
basePt.left += saveLeft;
basePt.right += saveRight;
/*
* if we don't inherit the the text justification
* set the new value.
*/
if (_DtCvINHERIT != _DtCvContainerJustifyOfSeg(con_seg))
{
layout->txt_justify = _DtCvContainerJustifyOfSeg(con_seg);
if (_DtCvJUSTIFY_NUM == layout->txt_justify)
layout->info.align_char = PeriodStr;
else if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
{
layout->info.align_char = _DtCvContainerJustifyCharOfSeg(con_seg);
/*
* check to see if the character is 'valid'.
* if not, default out of JUSTIFY_CHAR
*/
if ( (NULL != layout->info.align_char) && ( '\0' != *layout->info.align_char))
layout->txt_justify = _DtCvJUSTIFY_LEFT;
}
}
/*
* terminate the previous rendering list
*/
if (NULL != layout->lst_rendered)
layout->lst_rendered->next_disp = NULL;
layout->lst_rendered = NULL;
/*
* push the data point and reset margin/text info.
*/
PushDataPoint(layout, &basePt);
SetMargins(layout);
SetTextPosition(layout, True);
}
/*
* determine the minimum Y that the child of this container should
* occupy. To do so, subtract off the bottom border pad and the
* bottom margin.
*/
if (0 < min_y)
{
myMinY = min_y - yPad;
if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
{
_DtCvUnit bPad = 0;
_DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg), &bPad);
myMinY -= bPad;
}
}
/*
* format the segment
*/
saveYpos = layout->info.y_pos;
GetCurrentDataPoint(layout, &curPt);
/*
* reset the max x variable
*/
layout->info.cur_max_x = 0;
ProcessSegmentList(canvas, layout, _DtCvContainerListOfSeg(con_seg),
myMinY,
&maxWidth, &maxXPos, NULL);
/*
* if this container forces a wrap join of the next item,
* save the current line, but don't add space or null the
* last rendered item.
*/
CheckSaveInfo(canvas, layout, con_seg, 0);
if (maxWidth < layout->info.cur_max_x - curPt.left + layout->right)
maxWidth = layout->info.cur_max_x - curPt.left + layout->right;
if (maxXPos < layout->info.cur_max_x)
maxXPos = layout->info.cur_max_x;
if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
{
/*
* Save any information in the buffer,
* reset the margins and add the appropriate lines,
* and check for going over boundaries.
*/
_DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg),
&(layout->info.y_pos));
/*
* terminate the previous rendering list
*/
if (NULL != layout->lst_rendered)
layout->lst_rendered->next_disp = NULL;
layout->lst_rendered = NULL;
}
/*
* remove this element's data points from the stack.
*/
RemoveDataPoint(layout, &basePt);
/*
* include the bottom border (if needed) in the ending y position
*/
layout->info.y_pos += yPad;
/*
* Set the ending counts for the lines and text in me.
* This sets the ending counts for the lines contained in me,
* NOT the lines in my border.
*/
SetEndCounts(canvas, &(frmtInfo.cnt), 0);
/*
* does this object need to be adjust within its height?
*/
if (0 < min_y && layout->info.y_pos < min_y)
{
AdjustObjectPosition(canvas, layout, TxtVertJustify(con_seg),
frmtInfo.cnt.beg_txt, frmtInfo.cnt.beg_ln,
frmtInfo.cnt.beg_brk,
frmtInfo.cnt.end_txt, frmtInfo.cnt.end_ln,
frmtInfo.cnt.end_brk,
0, min_y - layout->info.y_pos - yPad, 0, 0, 0);
layout->info.y_pos = min_y;
}
/*
* Now draw the borders
* If borders are drawn, cur_max_x & max_x_pos may get changed
* if a right side border is drawn.
*/
if (maxWidth < layout->max_width - curPt.left - curPt.right)
maxWidth = layout->max_width - curPt.left - curPt.right;
getLn = DrawBorders (canvas, layout, Border(con_seg),
BrdData(con_seg), BrdWidth(con_seg),
saveYpos, layout->info.y_pos - yPad,
curPt.left,
curPt.left + maxWidth);
/*
* check to see if we need to save the container counts away
* because we might need to move the entire container as one
* to honor the boundary. This will occur if the flag to honor
* a boundary is set to _DtCvUSE_BOUNDARY_MOVE, this container has
* border lines, the container's parent is not a table nor
* is the container within another container that has a border.
*/
if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint
&& True == layout->brdr_flag
&& False == saveBrdr && False == layout->table_flag)
{
GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
/*
* warning - nothing done if malloc error.
*/
if (NULL != info)
{
/*
* initialize to the end information of the container.
*/
info->cnt = frmtInfo.cnt;
/*
* take into account the borders for this container
*/
SetEndCounts(canvas, &(info->cnt), getLn);
/*
* set the linked list information
*/
info->next_info = layout->grp_lst;
layout->grp_lst = info;
}
}
/*
* set the return values.
*/
*ret_max_x = layout->info.cur_max_x;
*ret_width = maxWidth;
if (*ret_width < layout->max_width - curPt.left - curPt.right)
*ret_width = layout->max_width - curPt.left - curPt.right;
/*
* Restore the previous information
*/
layout->left = saveLeft;
layout->right = saveRight;
layout->first = saveFirst;
layout->stat_flag = saveStatic;
layout->brdr_flag = saveBrdr;
layout->info.leading = saveLead;
/*
* Besides checking for flow constraints, also (re)sets margins and
* text information.
*/
CheckFormat(layout, True);
layout->txt_justify = saveJustify;
layout->info.align_char = saveJustifyChar;
/*
* for tables and such, return how many lines were drawn around this
* container.
*/
if (ret_cnt)
*ret_cnt = getLn;
return;
}
/******************************************************************************
* Function: ProcessSegmentList
*
* Process the segment list, laying it out according to left, right,
* and first margins specified. Returns the max_width of the all
* segments processed and the maximum x coordinate used.
*****************************************************************************/
static void
ProcessSegmentList(
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvSegmentI *cur_seg,
_DtCvUnit min_y,
_DtCvUnit *ret_width,
_DtCvUnit *ret_max_x,
int **ret_vert)
{
int junk;
int saveTravCnt = canvas->trav_cnt;
int saveTxtCnt = canvas->txt_cnt;
int saveLineCnt = canvas->line_cnt;
int saveBrkCnt = canvas->brk_cnt;
_DtCvUnit tempX;
_DtCvUnit tempLen;
_DtCvUnit width;
_DtCvUnit nWidth = 0;
_DtCvUnit leftMargin = 0;
_DtCvUnit rightMargin = 0;
_DtCvUnit topHeight = 0;
_DtCvUnit botHeight = 0;
_DtCvUnit maxWidth = 0;
_DtCvUnit saveYpos = layout->info.y_pos;
_DtCvSegmentI *segStart = cur_seg;
LayFrmtInfo *headInfo = NULL;
LayFrmtInfo *lastHead = NULL;
LayFrmtInfo *nxtHead;
_DtCvLayoutInfo startInfo;
_DtCvValue redo = False;
_DtCvValue joinCleared = False;
_DtCvValue flag;
TopDims topBot;
SideDims sideDims;
CornerDims cornerDims;
FlowDims flowDims;
DataPoint basePt;
DataPoint leftPt;
DataPoint rightPt;
/*
* clear the controller arrays
*/
InitDimArrays(&topBot, &sideDims, &cornerDims, &flowDims);
/*
* get the current left and right values or 'base'.
*/
GetCurrentDataPoint(layout, &basePt);
/*
* ???
*/
leftPt = basePt;
rightPt = basePt;
leftPt.y_pos = _CEFORMAT_ALL;
rightPt.y_pos = _CEFORMAT_ALL;
/*
* process all the controller type containers in the segment list
*/
while (NULL != cur_seg)
{
if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
{
/*
* want to clear this once and only once. Then any join
* directives will survive, though if two or more controllers
* have the directive set, the 'last' one will win out.
*/
if (False == joinCleared)
{
_DtCvSetJoinInfo(&(layout->info), False, -1);
joinCleared = True;
}
/*
* process the 'controller'
*/
nxtHead = ProcessController(canvas, layout, cur_seg);
/*
* update the dimension arrays so that the controller
* will get placed correctly.
*/
UpdateDimensionArrays(cur_seg, nxtHead->width, nxtHead->height,
&topBot, &sideDims, &cornerDims, &flowDims,
&leftMargin, &rightMargin);
/*
* remember this controller.
*/
if (NULL == headInfo)
headInfo = nxtHead;
else
lastHead->next_info = nxtHead;
lastHead = nxtHead;
}
/*
* go to the next segment
*/
cur_seg = cur_seg->next_seg;
}
/*
* Now reset the margins based on the controllers found
*/
if (NULL != headInfo)
{
DetermineMaxDims(&topBot, &cornerDims, leftMargin, rightMargin,
&topHeight, &botHeight, &maxWidth);
layout->info.y_pos += topHeight;
layout->left += leftMargin;
layout->right += rightMargin;
DetermineFlowConstraints(layout, flowDims,
basePt.left, basePt.right,
layout->info.y_pos, &leftPt, &rightPt);
/*
* get rid of the leftMargin and rightMargin values in maxWidth
* otherwise the use of layout->left & layout->right will double
* the value.
*/
maxWidth = maxWidth - leftMargin - rightMargin;
if (layout->max_width < maxWidth + basePt.left + basePt.right +
layout->left + layout->right)
layout->max_width = maxWidth + basePt.left + basePt.right +
layout->left + layout->right;
SetMargins(layout);
SetTextPosition(layout, True);
if (JoinSet(layout))
{
int cnt;
int joinLine = layout->info.join_line;
int start = canvas->txt_lst[joinLine].byte_index;
int count = canvas->txt_lst[joinLine].length;
_DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
_DtCvUnit tmpWidth;
/*
* change the starting location of the following text.
* take into account the left margin that *hasn't*
* been added to the controlling container.
*/
layout->info.text_x_pos = canvas->txt_lst[joinLine].text_x
+ layout->lmargin;
layout->info.cur_len = 0;
/*
* now calculate the width of this line.
*/
while (pSeg != NULL && count > 0)
{
_DtCvGetWidthOfSegment(canvas,pSeg,start,count,
&cnt, &tmpWidth, NULL);
layout->info.text_x_pos += tmpWidth;
count -= cnt;
start = 0;
pSeg = pSeg->next_disp;
}
}
}
/*
* now format for non-controller containers and non-containers.
* re-start at the beginning.
*/
cur_seg = segStart;
/*
* Save some information incase we have to redo the layout. I.e.
* we overflow the sizing.
*/
startInfo = layout->info;
saveTravCnt = canvas->trav_cnt;
saveTxtCnt = canvas->txt_cnt;
saveLineCnt = canvas->line_cnt;
saveBrkCnt = canvas->brk_cnt;
while (NULL != cur_seg)
{
width = layout->max_width - layout->info.text_x_pos
- layout->rmargin - layout->info.cur_len;
/*
* check to see if this item should start a line.
*/
CheckSetLineStart(layout, cur_seg);
/*
* check to see if this item will cause a page break.
*/
CheckForPageBreak(canvas, cur_seg, layout->info.y_pos);
switch (_DtCvPrimaryTypeOfSeg(cur_seg))
{
case _DtCvCONTAINER:
if (!(_DtCvIsSegController(cur_seg)))
ProcessContainer(canvas, layout, cur_seg, min_y,
&junk, &junk, &junk);
break;
case _DtCvREGION:
/*
* flag that this segment needs a line number
*/
cur_seg->internal_use = (void *) -1;
/*
* process the segment
*/
if (_DtCvIsSegInLine(cur_seg))
{
/*
* if a hypertext link, this will add it to
* the internal list.
*/
CheckAddToHyperList(canvas, cur_seg);
/*
* get the traversal width
*/
nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
layout->info.lst_hyper);
/*
* check to see if this region can end a line
*/
flag = _DtCvCheckLineSyntax(canvas,cur_seg,0,0,False);
/*
* if this can't end a line, get the length up to
* the next segment that can and base whether to
* save pased on that.
*/
tempLen = 0;
if (False == flag)
{
tempLen = _DtCvGetNextWidth(canvas,
_DtCvSTRING,
layout->info.lst_hyper,
cur_seg->next_seg,
0, cur_seg, NULL, NULL, NULL);
/*
* if the next width is zero, reset the flag.
*/
if (tempLen <= 0)
flag = True;
}
tempLen += nWidth;
/*
* if not joining, but my length goes over the
* working width, save out the current buffered
* information
*/
if (NotJoining(layout) &&
_DtCvWidthOfRegionSeg(cur_seg) + tempLen > width)
CheckSaveInfo (canvas, layout, cur_seg, 0);
/*
* up counts on the buffered information.
*/
layout->info.line_bytes += 1;
layout->info.cur_len +=
(_DtCvWidthOfRegionSeg(cur_seg) + nWidth);
/*
* does the next segment need to join with
* this one? If so, set the information
*/
_DtCvSetJoinInfo(&(layout->info), (flag ? 0 : 1), -1);
if (_DtCvIsSegNewLine(cur_seg))
SaveInfo(canvas, layout, cur_seg, 0);
}
else
{
/*
* clear out the join information
* standalone figures can't join with others.
*/
_DtCvSetJoinInfo(&(layout->info), False, -1);
/*
* figures are standalone. Save any
* information in the buffer away.
*/
CheckSaveInfo (canvas, layout, cur_seg, 0);
/*
* check to see if this segment is
* a hypertext. If so, add it to the
* list if it hasn't been added yet.
*/
CheckAddToHyperList(canvas, cur_seg);
/*
* get the traversal width, if any.
*/
nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
layout->info.lst_hyper);
/*
* now save the standalone figure
*/
layout->info.line_bytes += 1;
layout->info.cur_len +=
_DtCvWidthOfRegionSeg(cur_seg) + nWidth;
SaveInfo(canvas, layout, cur_seg->next_seg, 0);
/*
* check for wrapping overflow
*/
CheckFormat(layout, False);
}
/*
* indicate this segment as the last item rendered
*/
if (NULL != layout->lst_rendered)
layout->lst_rendered->next_disp = cur_seg;
layout->lst_rendered = cur_seg;
break;
case _DtCvLINE:
/*
* lines are standalone. Save any
* information in the buffer away.
*/
CheckSaveInfo (canvas, layout, cur_seg, 0);
/*
* if the line_width is zero, make it 1 so
* that it really does take some space.
*/
nWidth = _DtCvWidthOfLineSeg(cur_seg);
if (0 == nWidth)
nWidth = 1;
/*
* start with it going all the way across the window.
*/
width = layout->max_width;
tempX = 0;
/*
* or does it only extend across the container?
*/
if (_DtCvIsSegBlockLine(cur_seg))
{
tempX = layout->lmargin;
width = layout->max_width - tempX - layout->rmargin;
}
SaveLine (canvas, layout, _DtCvLINE_HORZ,
_DtCvDataOfLineSeg(cur_seg), nWidth, tempX,
layout->info.y_pos, width);
layout->info.y_pos += nWidth;
break;
case _DtCvMARKER:
/*
* check to see if marker is the target id
*/
CheckId(layout, _DtCvIdOfMarkerSeg(cur_seg));
break;
case _DtCvNOOP:
if (_DtCvIsSegNewLine(cur_seg))
SaveInfo(canvas, layout, cur_seg, 0);
break;
case _DtCvSTRING:
/*
* flag that this segment needs a line number
*/
cur_seg->internal_use = (void *) -1;
/*
* process the string
*/
ProcessStringSegment(canvas, layout, cur_seg);
/*
* check for wrapping overflow.
*/
if (_DtCvIsSegNewLine(cur_seg))
CheckFormat(layout, False);
/*
* indicate this segment as the last item rendered
*/
if (NULL != layout->lst_rendered)
layout->lst_rendered->next_disp = cur_seg;
layout->lst_rendered = cur_seg;
break;
case _DtCvTABLE:
ProcessTable(canvas, layout, cur_seg, min_y);
default:
break;
}
/*
* get the next segment
*/
cur_seg = cur_seg->next_seg;
/*
* check the flowing text points
*/
if (leftPt.y_pos > 0 &&
leftPt.x_units > layout->max_width - leftPt.left - leftPt.right)
{
layout->max_width = leftPt.x_units + leftPt.left + leftPt.right;
redo = True;
}
if (rightPt.y_pos > 0 &&
rightPt.x_units > layout->max_width-rightPt.left-rightPt.right)
{
layout->max_width = rightPt.x_units + rightPt.left + rightPt.right;
redo = True;
}
/*
* have we violated the available space?
* if so, we'll have to reformat.
*/
if (redo == True)
{
redo = False;
cur_seg = segStart;
canvas->trav_cnt = saveTravCnt;
canvas->txt_cnt = saveTxtCnt;
canvas->line_cnt = saveLineCnt;
canvas->brk_cnt = saveBrkCnt;
layout->info = startInfo;
if (rightPt.y_pos > 0)
{
RemoveDataPoint(layout, &rightPt); /* make sure its gone */
InsertDataPoint(layout, &rightPt);
}
if (leftPt.y_pos > 0)
{
RemoveDataPoint(layout, &leftPt); /* make sure its gone */
InsertDataPoint(layout, &leftPt);
}
/*
* Now reset the margins based on the controllers found
*/
if (NULL != headInfo)
{
layout->left += leftMargin;
layout->right += rightMargin;
SetMargins(layout);
SetTextPosition(layout, True);
if (JoinSet(layout))
{
int cnt;
int joinLine = layout->info.join_line;
int start = canvas->txt_lst[joinLine].byte_index;
int count = canvas->txt_lst[joinLine].length;
_DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
_DtCvUnit tmpWidth;
/*
* change the starting location of the following text.
* take into account the left margin that *hasn't*
* been added to the controlling container.
*/
layout->info.text_x_pos = canvas->txt_lst[joinLine].text_x
+ layout->lmargin;
layout->info.cur_len = 0;
/*
* now calculate the width of this line.
*/
while (pSeg != NULL && count > 0)
{
_DtCvGetWidthOfSegment(canvas,pSeg,start,count,
&cnt, &tmpWidth, NULL);
layout->info.text_x_pos += tmpWidth;
count -= cnt;
start = 0;
pSeg = pSeg->next_disp;
}
}
}
}
}
RemoveDataPoint(layout, &leftPt);
RemoveDataPoint(layout, &rightPt);
/*
* if there were heads, now place them correctly.
*/
if (NULL != headInfo)
{
_DtCvUnit blockHeight;
_DtCvUnit blockWidth;
/*
* make sure all of the information in the body is saved out
*/
CheckSaveInfo (canvas, layout, NULL, 0);
/*
* now calculate the non-controllers overall height.
*/
blockHeight = layout->info.y_pos - saveYpos - topHeight;
/*
* now figure the head positions.
*/
DetermineHeadPositioning(&topBot, &sideDims, &cornerDims, &flowDims,
saveYpos, topHeight,
blockHeight, &blockHeight);
/*
* if the maximum available space was exceeded by the text
* calculate a new max width
*/
if (layout->max_width < layout->info.cur_max_x + layout->right)
layout->max_width = layout->info.cur_max_x + layout->right;
blockWidth = layout->max_width - basePt.left - basePt.right
- layout->left - layout->right;
nxtHead = headInfo;
cur_seg = segStart;
while (cur_seg != NULL)
{
if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
{
AdjustHeadPosition(canvas, layout, cur_seg,
&topBot, &sideDims, &cornerDims, &flowDims, nxtHead,
0, basePt.left + layout->left - leftMargin, blockWidth,
leftMargin, rightMargin);
/*
* go to the next head element
*/
nxtHead = nxtHead->next_info;
/*
* free the information.
*/
free(headInfo);
headInfo = nxtHead;
}
/*
* got to the next segment
*/
cur_seg = cur_seg->next_seg;
}
if (layout->info.y_pos < saveYpos + topHeight + blockHeight)
layout->info.y_pos = saveYpos + topHeight + blockHeight;
layout->info.y_pos += botHeight;
}
/*
* set the return values
*/
*ret_width = layout->info.cur_max_x - basePt.left + layout->right;
*ret_max_x = layout->info.cur_max_x;
return;
}
/*****************************************************************************
* Function: static _DtCvUnit MaxOfGroup (
*
* Purpose: Determine the maximum of a group.
*****************************************************************************/
static void
MaxOfGroup (
GrpInfo *group,
_DtCvDspLine *text,
_DtCvLineSeg *lines,
_DtCvUnit max_x,
_DtCvUnit max_y)
{
int i;
/*
* initialize
*/
group->min_x = max_x;
group->max_x = 0;
group->top_y = max_y;
group->bot_y = 0;
/*
* find the maximum of the group
*/
for (i = group->cnt.beg_txt; i < group->cnt.end_txt; i++)
{
/*
* check for min's and max's
*/
if (group->min_x > text[i].text_x)
group->min_x = text[i].text_x;
if (group->max_x < text[i].max_x)
group->max_x = text[i].max_x;
if (group->top_y > text[i].baseline - text[i].ascent)
group->top_y = text[i].baseline - text[i].ascent;
if (group->bot_y < text[i].baseline + text[i].descent)
group->bot_y = text[i].baseline + text[i].descent;
/*
* indicate that this line has been processed already
*/
_DtCvSetProcessed(text[i]);
}
for (i = group->cnt.beg_ln; i < group->cnt.end_ln; i++)
{
/*
* check for min's and max's
*/
if (group->min_x > lines[i].pos_x)
group->min_x = lines[i].pos_x;
if (group->max_x < lines[i].max_x)
group->max_x = lines[i].max_x;
if (group->top_y > lines[i].pos_y)
group->top_y = lines[i].pos_y;
if (group->bot_y < lines[i].max_y)
group->bot_y = lines[i].max_y;
/*
* indicate that this line has been processed already
*/
_DtCvSetProcessed(lines[i]);
}
}
/*****************************************************************************
* Function: static _DtCvUnit TestSpacing (
*
* Parameters:
*
* Returns: True if the object is before (x wise) the test object.
* False if the object is not before (x wise) the text object.
*
* Purpose:
*
*****************************************************************************/
static _DtCvStatus
TestSpacing (
_DtCvUnit tst_top,
_DtCvUnit tst_bot,
_DtCvUnit tst_min,
_DtCvUnit obj_top,
_DtCvUnit obj_bot,
_DtCvUnit obj_max,
_DtCvUnit needed,
_DtCvUnit min_space,
_DtCvUnit *ret_amount)
{
_DtCvStatus result = False;
/*
* check to see if the object is to the left of the test object
* to move and that it 'infringes' on the vertical
* space of the test object.
*
* I.e. ----obj_top------
* | | ----tst_top----
* ----obj_bot------ | |
* ----tst_bot----
*
* I.e. ----tst_top----
* ----obj_top------- | |
* | | ----tst_bot----
* ----obj_bot-------
*
* I.e. ----obj_top------
* | | ----tst_top----
* | | | |
* | | ----tst_bot----
* ----obj_bot------
*
* I.e. ----tst_top----
* ----obj_top------- | |
* | | | |
* ----obj_bot------- | |
* ----tst_bot----
*/
if (obj_max < tst_min
&& True == _DtCvCheckInfringement(tst_top, tst_bot, obj_top, obj_bot)
&& needed > tst_min - obj_max)
{
/*
* okay, this infringes on the object's space.
* truncate the amount of room there is to move the object
*/
result = True;
needed = tst_min - obj_max;
/*
* is the space between these two objects already squeezed
* below the minimum allowed?
*/
if (needed < min_space)
needed = 0;
else /* leave the minimum space between the objects */
needed -= min_space;
}
*ret_amount = needed;
return result;
}
/*****************************************************************************
* Function: static void MoveLeft (
*
* Parameters:
*
* Returns:
*
* Purpose: Moves the object's rules/lines and text lines to the left.
*
*****************************************************************************/
static void
MoveLeft (
_DtCanvasStruct *canvas,
int beg_txt,
int end_txt,
int beg_ln,
int end_ln,
_DtCvUnit space)
{
int i;
/*
* bail now if nothing to do.
*/
if (1 > space)
return;
/*
* move each text/region line.
*/
for (i = beg_txt; i < end_txt; i++)
{
canvas->txt_lst[i].text_x -= space;
canvas->txt_lst[i].max_x -= space;
}
/*
* move each line/rule.
*/
for (i = beg_ln; i < end_ln; i++)
{
canvas->line_lst[i].pos_x -= space;
canvas->line_lst[i].max_x -= space;
}
}
/*****************************************************************************
* Function: static _DtCvUnit CheckSpacing (
*
* Purpose: Check the spacing before an object and move any objects
* before it to the left to make room.
*
*****************************************************************************/
static _DtCvUnit
CheckSpacing (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
GrpInfo *tst_grp,
int txt_idx,
int line_idx,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit min_x,
_DtCvUnit needed)
{
int i;
_DtCvUnit space;
_DtCvUnit maxSpace;
_DtCvUnit topY;
_DtCvUnit botY;
GrpInfo *nxtGrp = layout->grp_lst;
/*
* truncate if the amount needed is more than available.
*/
if (min_x < needed)
needed = min_x;
maxSpace = needed;
/*
* see what group is before this group and how much space there is
*/
while (NULL != nxtGrp)
{
/*
* as long as I'm not comparing against myself, try it.
*/
if (nxtGrp != tst_grp)
{
/*
* is this group before(x wise) the test group, infringing
* upon the test group's top and bottom positioning (y)
* and is the amount of space (x wise) between them smaller
* than the current smallest space found?
*/
if (True == TestSpacing (top_y, bot_y, min_x,
nxtGrp->top_y, nxtGrp->bot_y,
nxtGrp->max_x, needed,
canvas->metrics.horiz_pad_hint,
&space))
{
space += MoveGroup(canvas, layout, nxtGrp, needed - space);
if (maxSpace > space)
maxSpace = space;
}
}
/*
* check the next group
*/
nxtGrp = nxtGrp->next_info;
}
/*
* look at each of the text lines;
*/
for (i = 0; i < canvas->txt_cnt; i++)
{
/*
* Only look at those lines not already processed.
*/
if (i != txt_idx && _DtCvIsNotProcessed(canvas->txt_lst[i]))
{
topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
canvas->txt_lst[i].max_x, needed,
canvas->metrics.horiz_pad_hint, &space))
{
space += MoveText(canvas, layout, i, topY, botY, needed-space);
if (maxSpace > space)
maxSpace = space;
}
}
}
/*
* look at each of the rules/lines;
*/
for (i = 0; i < canvas->line_cnt; i++)
{
/*
* Only look at those lines not already processed.
*/
if (i != line_idx && _DtCvIsNotProcessed(canvas->line_lst[i]))
{
/*
* calculate the top and bottom of the line
*/
topY = canvas->line_lst[i].pos_y;
botY = canvas->line_lst[i].max_y;
if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
canvas->line_lst[i].max_x, needed,
canvas->metrics.horiz_pad_hint, &space))
{
space += MoveLines(canvas, layout, i, topY, botY, needed-space);
if (maxSpace > space)
maxSpace = space;
}
}
}
return maxSpace;
}
/*****************************************************************************
* Function: static _DtCvUnit MoveGroup (_DtCanvasStruct canvas);
*
* Purpose: To move groupings (container, tables, etc.) as a group to
* honor boundaries.
*
*****************************************************************************/
static _DtCvUnit
MoveGroup (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
GrpInfo *tst_grp,
_DtCvUnit needed)
{
_DtCvUnit space;
/*
* find out what's in front of it. And how much 'extra' room
* there is.
*/
space = CheckSpacing(canvas, layout, tst_grp, -1, -1,
tst_grp->top_y, tst_grp->bot_y, tst_grp->min_x,
needed);
/*
* now move the group
*/
MoveLeft(canvas, tst_grp->cnt.beg_txt, tst_grp->cnt.end_txt,
tst_grp->cnt.beg_ln, tst_grp->cnt.end_ln, space);
tst_grp->max_x -= space;
tst_grp->min_x -= space;
return space;
}
/*****************************************************************************
* Function: static _DtCvUnit MoveText (_DtCanvasStruct canvas);
*
* Purpose: To move text lines to honor boundaries.
*
*****************************************************************************/
static _DtCvUnit
MoveText (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
int idx,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit needed)
{
_DtCvUnit space;
/*
* find out what's in front of it. And how much 'extra' room
* there is.
*/
space = CheckSpacing(canvas, layout, NULL, idx, -1,
top_y, bot_y,
canvas->txt_lst[idx].text_x,
needed);
/*
* now move the group
*/
MoveLeft(canvas, idx, idx, -1, -1, space);
return space;
}
/*****************************************************************************
* Function: static _DtCvUnit MoveLines (_DtCanvasStruct canvas);
*
* Purpose: To move groupings (container, tables, etc.) as a group to
* honor boundaries.
*
*****************************************************************************/
static _DtCvUnit
MoveLines (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
int idx,
_DtCvUnit top_y,
_DtCvUnit bot_y,
_DtCvUnit needed)
{
_DtCvUnit space;
/*
* find out what's in front of it. And how much 'extra' room
* there is.
*/
space = CheckSpacing(canvas, layout, NULL, -1, idx,
top_y, bot_y,
canvas->line_lst[idx].pos_x,
needed);
/*
* now move the group
*/
MoveLeft(canvas, -1, -1, idx, idx, space);
return space;
}
/*****************************************************************************
* Function: static void CheckMoveInfo (_DtCanvasStruct canvas);
*
* Purpose: To move each of the groupings, rules and text lines to
* honor boundaries.
*
*****************************************************************************/
static void
CheckMoveInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout)
{
int i;
_DtCvUnit topY;
_DtCvUnit botY;
_DtCvUnit maxWidth = canvas->metrics.width;
GrpInfo *nxtGrp;
/*
* fill in the max x of each group
*/
for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
{
/*
* find the maximum of the group
*/
MaxOfGroup(nxtGrp, canvas->txt_lst, canvas->line_lst,
layout->info.max_x_pos, layout->info.y_pos);
}
/*
* now check each group for exceeding the boundary.
*/
for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
{
/*
* does this group exceed the boundary?
*/
if (maxWidth < nxtGrp->max_x)
(void) MoveGroup(canvas, layout, nxtGrp, nxtGrp->max_x - maxWidth);
}
/*
* look at each of the text lines;
*/
for (i = 0; i < canvas->txt_cnt; i++)
{
/*
* Only look at those lines not already processed.
*/
if (_DtCvIsNotProcessed(canvas->txt_lst[i]) &&
maxWidth < canvas->txt_lst[i].max_x)
{
topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
(void) MoveText(canvas, layout, i, topY, botY,
canvas->txt_lst[i].max_x - maxWidth);
}
}
/*
* look at each of the rules/lines;
*/
for (i = 0; i < canvas->line_cnt; i++)
{
/*
* Only look at those lines not already processed.
*/
if (_DtCvIsNotProcessed(canvas->line_lst[i]) &&
maxWidth < canvas->line_lst[i].max_x)
{
/*
* calculate the top and bottom of the line
*/
topY = canvas->line_lst[i].pos_y;
botY = canvas->line_lst[i].max_y;
(void) MoveLines(canvas, layout, i, topY, botY,
canvas->line_lst[i].max_x - maxWidth);
}
}
}
/*****************************************************************************
* Function: static void CompareUnits ()
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static int
CompareUnits (
const void *a,
const void *b)
{
_DtCvUnit *aPtr = (_DtCvUnit *) a;
_DtCvUnit *bPtr = (_DtCvUnit *) b;
if (*aPtr < *bPtr) return -1;
if (*aPtr == *bPtr) return 0;
return 1;
}
/*****************************************************************************
* Function: static void CompareSearchs ()
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static int
CompareSearchs (
const void *a,
const void *b)
{
_DtCvSearchData *searchA = (_DtCvSearchData *) a;
_DtCvSearchData *searchB = (_DtCvSearchData *) b;
_DtCvDspLine *lineA = &(searchA->lst[searchA->idx]);
_DtCvDspLine *lineB = &(searchB->lst[searchB->idx]);
_DtCvUnit topA = lineA->baseline - lineA->ascent;
_DtCvUnit topB = lineB->baseline - lineB->ascent;
_DtCvUnit heightA = lineA->ascent + lineA->descent;
_DtCvUnit heightB = lineB->ascent + lineB->descent;
_DtCvUnit centA = topA + (heightA >> 1);
_DtCvUnit centB = topB + (heightB >> 1);
if (lineA->baseline + lineA->descent < centB && centA < topB)
return -1;
if (lineB->baseline + lineB->descent < centA && centB < topA)
return 1;
if (lineA->text_x != lineB->text_x)
return ((lineA->text_x < lineB->text_x) ? -1 : 1);
if (topA != topB)
return ((topA < topB) ? -1 : 1);
if (heightA != heightB)
return ((heightA < heightB) ? -1 : 1);
if (lineA->max_x != lineB->max_x)
return ((lineA->max_x < lineB->max_x) ? -1 : 1);
return 0;
}
/*****************************************************************************
* Function: static Status LayoutCanvasInfo (_DtCvHandle canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static _DtCvStatus
LayoutCanvasInfo (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
_DtCvUnit divisor,
char *target_id)
{
int i = 0;
DataPoint basePt;
_DtCvUnit maxWidth = 0;
_DtCvUnit maxXPos = 0;
_DtCvStatus result = _DtCvSTATUS_OK;
*layout = DefInfo;
layout->divisor = divisor;
layout->max_width = canvas->metrics.width;
layout->left = canvas->metrics.side_margin;
layout->right = canvas->metrics.side_margin;
layout->target_id = target_id;
_DtCvInitLayoutInfo(canvas, &(layout->info));
basePt = DefDataPt;
PushDataPoint(layout, &basePt);
SetMargins (layout);
SetTextPosition (layout, True);
ProcessSegmentList(canvas, layout, canvas->element_lst, -1,
&maxWidth, &maxXPos, NULL);
RemoveDataPoint(layout, &basePt);
/*
* fill in the max_x of each line of text/regions.
*/
for (i = 0; i < canvas->txt_cnt; i++)
canvas->txt_lst[i].max_x = MaxXOfLine(canvas, &(canvas->txt_lst[i]));
/*
* calculate the actual right hand side boundary.
*/
layout->info.max_x_pos += canvas->metrics.side_margin;
/*
* the max_x_pos so far has indicated where the *next* character,
* line or region will be *started*. Therefore back up one to
* indicate the true last position used.
*/
layout->info.max_x_pos--;
return result;
} /* End LayoutCanvasInfo */
/*****************************************************************************
* Function: static Status LayoutCanvas (_DtCvHandle canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static _DtCvStatus
LayoutCanvas (
_DtCanvasStruct *canvas,
LayoutInfo *layout,
char *target_id)
{
_DtCvUnit divisor = 1;
_DtCvValue redo;
_DtCvStatus result;
int i, search_cnt = canvas->search_cnt;
do {
redo = False;
result = LayoutCanvasInfo(canvas, layout, divisor, target_id);
/*
* Are we suppose to honor the boundary?
* If so, do any lines go over the boundary?
* Is there any margins that can be decremented?
*/
if (_DtCvSTATUS_OK == result
&& (_DtCvUSE_BOUNDARY == canvas->constraint ||
_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
&& layout->info.max_x_pos >= canvas->metrics.width)
{
if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
{
int i;
/*
* clear the processed flag from all the text/region lines.
*/
for (i = 0; i < canvas->txt_cnt; i++)
_DtCvClearProcessed(canvas->txt_lst[i]);
/*
* clear the processed flag from all the line/rules.
*/
for (i = 0; i < canvas->line_cnt; i++)
_DtCvClearProcessed(canvas->line_lst[i]);
CheckMoveInfo(canvas, layout);
/*
* recalculate the new max x
*/
layout->info.max_x_pos = 0;
for (i = 0; i < canvas->txt_cnt; i++)
if (layout->info.max_x_pos < canvas->txt_lst[i].max_x)
layout->info.max_x_pos = canvas->txt_lst[i].max_x;
for (i = 0; i < canvas->line_cnt; i++)
if (layout->info.max_x_pos < canvas->line_lst[i].max_x)
layout->info.max_x_pos = canvas->line_lst[i].max_x;
layout->info.max_x_pos--;
}
else if (True == layout->margin_non_zero)
{
redo = True;
divisor *= 2;
canvas->txt_cnt = 0;
canvas->line_cnt = 0;
canvas->trav_cnt = 0;
}
}
} while (True == redo);
/*
* clean up table information
*/
if (NULL != layout->grp_lst)
free(layout->grp_lst);
/*
* subtract one from the y position to indicate the *last*
* pixel/column/etc that will be rendered.
*/
canvas->max_y = layout->info.y_pos - 1;
canvas->max_x = layout->info.max_x_pos;
for (i = search_cnt; i < canvas->search_cnt; i++)
{
canvas->searchs[i - search_cnt] = canvas->searchs[i];
canvas->searchs[i - search_cnt].lst = canvas->txt_lst;
}
canvas->search_cnt -= search_cnt;
/*
* are there any search hits?
*/
if (0 != canvas->search_cnt)
qsort (canvas->searchs, canvas->search_cnt, sizeof(_DtCvSearchData),
CompareSearchs);
/*
* sort the page break list.
*/
if (0 != canvas->brk_cnt)
qsort (canvas->pg_breaks, canvas->brk_cnt, sizeof(_DtCvUnit),
CompareUnits);
return result;
} /* End LayoutCanvas */
/*****************************************************************************
* Function: static void SortTraversal (_DtCvHandle canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static void
SortTraversal (_DtCanvasStruct *canvas)
{
int i;
/*
* sort the links correctly. First, establish the x,y,width,height
* of each link.
*/
for (i = 0; i < canvas->trav_cnt; i++)
{
if (_DtCvTraversalLink == canvas->trav_lst[i].type)
GetLinkInfo(canvas, i, &(canvas->trav_lst[i].x_pos),
&(canvas->trav_lst[i].y_pos),
&(canvas->trav_lst[i].width),
&(canvas->trav_lst[i].height));
else
_DtCvCalcMarkPos(canvas, canvas->trav_lst[i].idx,
&(canvas->trav_lst[i].x_pos),
&(canvas->trav_lst[i].y_pos),
&(canvas->trav_lst[i].width),
&(canvas->trav_lst[i].height));
}
_DtCvSortTraversalList(canvas, _DtCvFALSE);
}
/*****************************************************************************
* Function: static void ProcessMarks (_DtCanvasStruct *canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
static _DtCvStatus
ProcessMarks (
_DtCanvasStruct *canvas,
_DtCvPointInfo **mark_lst)
{
int markIdx;
int result = _DtCvSTATUS_OK;
_DtCvSelectData beg;
_DtCvSelectData end;
_DtCvSegmentI *firstSeg;
while (NULL != mark_lst && NULL != *mark_lst)
{
/*
* convert the segments to begin and end points
*/
if (_DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, (*mark_lst)->segs,
&beg, &end, NULL, NULL, &firstSeg))
/*
* just set a return value since this indicates bad data
* and not system failure.
*/
result = _DtCvSTATUS_BAD;
/*
* now add it to the mark list
*/
else
{
markIdx = _DtCvAddToMarkList(canvas, (*mark_lst)->client_data,
_DtCvFALSE, &beg, &end);
/*
* now put the mark in the traversal list, but don't sort
* or fill out position and dimension information.
* SortTraversal() will do that.
*
* bail here if system failure indicated.
*/
if (-1 == markIdx || 0 != _DtCvSetTravEntryInfo(canvas,
_DtCvGetNextTravEntry(canvas),
_DtCvTraversalMark, firstSeg,
markIdx, _DtCvTRUE))
return _DtCvSTATUS_BAD;
}
mark_lst++;
}
return result;
}
/*****************************************************************************
* Public Functions
*****************************************************************************/
/*****************************************************************************
* Function: void _DtCanvasResize (_DtCvHandle canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasResize (
_DtCvHandle canvas_handle,
_DtCvValue force,
_DtCvUnit *ret_width,
_DtCvUnit *ret_height )
{
int i;
_DtCvStatus selectStatus;
_DtCvStatus retStatus = _DtCvSTATUS_NONE;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
_DtCvUnit oldWidth = canvas->metrics.width;
LayoutInfo layOut;
_DtCvPointInfo selPt;
_DtCvPointInfo **markInfo;
selPt.client_data = NULL;
selPt.segs = NULL;
/*
* check to see if the width has changed - if not,
* don't do anything (but re-initialize the metrics
* to get the new height).
*/
(*(canvas->virt_functions.get_metrics))(canvas->client_data,
_DtCvCANVAS_TYPE, &(canvas->metrics));
if (canvas->metrics.width != oldWidth || _DtCvTRUE == force)
{
/*
* remember the current selection.
*/
selectStatus = _DtCanvasGetSelectionPoints(canvas, &(selPt.segs),
NULL, NULL);
/*
* remember the marks
*/
if (_DtCvSTATUS_BAD == _DtCvGetMarkSegs(canvas, &markInfo))
return _DtCvSTATUS_BAD;
/*
* Re-Layout the information.
* First step - invalidate some counters.
*/
canvas->trav_cnt = 0; /* zero this only because we re-process */
/* do not zero cur_hyper or we'll loose */
/* where we are in the TOC */
canvas->txt_cnt = 0;
canvas->line_cnt = 0;
canvas->mark_cnt = 0;
canvas->brk_cnt = 0;
/*
* Layout the information if there is anything to do
*/
if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, NULL))
return _DtCvSTATUS_BAD;
/*
* restore the current selection.
*/
if (_DtCvSTATUS_OK == selectStatus)
{
_DtCanvasActivatePts(canvas,_DtCvACTIVATE_SELECTION, &selPt,
NULL,NULL);
_DtCvFreeArray((void **) selPt.segs);
}
/*
* now place the marks in the mark and traversal lists
*/
ProcessMarks(canvas, markInfo);
if (NULL != markInfo)
{
for (i = 0; NULL != markInfo[i]; i++)
_DtCvFreeArray((void **) (markInfo[i]->segs));
_DtCvFreeArray((void **) markInfo);
}
/*
* sort the traversal list.
*/
SortTraversal(canvas);
retStatus = _DtCvSTATUS_OK;
}
/*
* return the maximum height and width used
*/
if (ret_width != NULL)
*ret_width = canvas->max_x;
if (ret_height != NULL)
*ret_height = canvas->max_y;
return retStatus;
} /* End _DtCanvasResize */
/*****************************************************************************
* Function: void _DtCanvasSetTopic (_DtCvHandle canvas);
*
* Parameters:
*
* Returns:
*
* Purpose:
*
*****************************************************************************/
_DtCvStatus
_DtCanvasSetTopic (
_DtCvHandle canvas_handle,
_DtCvTopicPtr topic,
_DtCvValue honor_size,
_DtCvUnit *ret_width,
_DtCvUnit *ret_height,
_DtCvUnit *ret_y )
{
_DtCvStatus result = _DtCvSTATUS_OK;
_DtCanvasStruct *canvas = (_DtCanvasStruct *) canvas_handle;
LayoutInfo layOut;
/*
* clean the canvas
*/
_DtCanvasClean (canvas_handle);
/*
* attach to the canvas
*/
canvas->element_lst = topic->seg_list;
/*
* Attach the link information
*/
canvas->link_data = topic->link_data;
/*
* init the internal use pointer in all containers to NULL
*/
_DtCvClearInternalUse(canvas->element_lst, _DtCvFALSE);
/*
* Layout the information if there is anything to do
*/
canvas->constraint = honor_size;
if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, topic->id_str))
return _DtCvSTATUS_BAD;
/*
* add the marks to the mark and traversal lists
*/
ProcessMarks(canvas, topic->mark_list);
/*
* sort the traversal list.
*/
SortTraversal(canvas);
/*
* return the maximum height and width used
* And the location of the id.
*/
if (ret_width != NULL)
*ret_width = canvas->max_x;
if (ret_height != NULL)
*ret_height = canvas->max_y;
if (ret_y != NULL)
{
if (NULL != layOut.target_id && True != layOut.id_found)
result = _DtCvSTATUS_ID_BAD;
*ret_y = layOut.id_Ypos;
}
return result;
} /* End _DtCanvasSetTopic */