mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
5690 lines
149 KiB
C
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 */
|