summaryrefslogtreecommitdiffstats
path: root/tkhtml1/src/htmltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'tkhtml1/src/htmltable.c')
-rw-r--r--tkhtml1/src/htmltable.c1175
1 files changed, 0 insertions, 1175 deletions
diff --git a/tkhtml1/src/htmltable.c b/tkhtml1/src/htmltable.c
deleted file mode 100644
index 98bbb48..0000000
--- a/tkhtml1/src/htmltable.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-/*
-** Routines for doing layout of HTML tables
-**
-** Copyright (C) 1997-2000 D. Richard Hipp
-**
-** This library is free software; you can redistribute it and/or
-** modify it under the terms of the GNU Library General Public
-** License as published by the Free Software Foundation; either
-** version 2 of the License, or (at your option) any later version.
-**
-** This library is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** Library General Public License for more details.
-**
-** You should have received a copy of the GNU Library General Public
-** License along with this library; if not, write to the
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-** Boston, MA 02111-1307, USA.
-**
-** Author contact information:
-** drh@acm.org
-** http://www.hwaci.com/drh/
-*/
-#include <tk.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include "htmltable.h"
-
-/*
-** Default values for various table style parameters
-*/
-#define DFLT_BORDER 0
-#define DFLT_CELLSPACING_3D 5
-#define DFLT_CELLSPACING_FLAT 0
-#define DFLT_CELLPADDING 2
-#define DFLT_HSPACE 0
-#define DFLT_VSPACE 0
-
-#if INTERFACE
-/*
-** Set parameter A to the maximum of A and B.
-*/
-#define SETMAX(A,B) if( (A)<(B) ){ (A) = (B); }
-#define MAX(A,B) ((A)<(B)?(B):(A))
-#endif
-
-/*
-** Return the appropriate cell spacing for the given table.
-*/
-static int CellSpacing(HtmlWidget *htmlPtr, HtmlElement *pTable){
- char *z;
- int relief;
- int cellSpacing;
-
- z = HtmlMarkupArg(pTable, "cellspacing", 0);
- if( z==0 ){
- relief = htmlPtr->tableRelief;
- if( relief==TK_RELIEF_RAISED || relief==TK_RELIEF_SUNKEN ){
- cellSpacing = DFLT_CELLSPACING_3D;
- }else{
- cellSpacing = DFLT_CELLSPACING_FLAT;
- }
- }else{
- cellSpacing = atoi(z);
- }
- return cellSpacing;
-}
-
-/* Forward declaration */
-static HtmlElement *MinMax(HtmlWidget*, HtmlElement *, int *, int *, int);
-
-/* pStart points to a <table>. Compute the number of columns, the
-** minimum and maximum size for each column and the overall minimum
-** and maximum size for this table and store these value in the
-** pStart structure. Return a pointer to the </table> element,
-** or to NULL if there is no </table>.
-**
-** The min and max size for column N (where the leftmost column has
-** N==1) is pStart->minW[1] and pStart->maxW[1]. The pStart->minW[0]
-** and pStart->maxW[0] entries contain the minimum and maximum widths
-** of the whole table, including any cell padding, cell spacing,
-** border width and "hspace". The values of pStart->minW[I] for I>=1
-** do not contain any cell padding, cell spacing or border width.
-** Only pStart->minW[0] contains these extra spaces.
-**
-** The back references from </table>, </tr>, </td> and </th> back to
-** the <table> markup are also filled in. And for each <td> and <th>
-** markup, the pTable and pEnd fields are set to their proper values.
-*/
-static HtmlElement *TableDimensions(
- HtmlWidget *htmlPtr, /* The HTML widget */
- HtmlElement *pStart, /* The <table> markup */
- int lineWidth /* Total widget available to the table */
-){
- HtmlElement *p; /* Element being processed */
- HtmlElement *pNext; /* Next element to process */
- int iCol = 0; /* Current column number. 1..N */
- int iRow = 0; /* Current row number */
- int inRow = 0; /* True if in between <TR> and </TR> */
- int i, j; /* Loop counters */
- int n; /* Number of columns */
- int minW, maxW, requestedW; /* min, max, requested width for a cell */
- int noWrap; /* true for NOWRAP cells */
- int colspan; /* Column span for the current cell */
- int rowspan; /* Row span for the current cell */
- char *z; /* Value of a <table> parameter */
- int cellSpacing; /* Value of CELLSPACING parameter */
- int cellPadding; /* Value of CELLPADDING parameter */
- int tbw; /* Width of border around whole table */
- int cbw; /* Width of border around one cell */
- int hspace; /* Value of HSPACE parameter */
- int separation; /* Space between columns */
- int margin; /* Space between left margin and 1st col */
- int availWidth; /* Part of lineWidth still available */
- int maxTableWidth; /* Amount of lineWidth available to table*/
- int fromAbove[HTML_MAX_COLUMNS+1]; /* Cell above extends thru this row */
- int min0span[HTML_MAX_COLUMNS+1]; /* Min for colspan=0 cells */
- int max0span[HTML_MAX_COLUMNS+1]; /* Max for colspan=0 cells */
- int reqW[HTML_MAX_COLUMNS+1]; /* Requested width for each column */
-
- /* colMin[A][B] is the absolute minimum width of all columns between
- ** A+1 and B+1. colMin[B][A] is the requested width of columns between
- ** A+1 and B+1. This information is used to add in the constraints imposed
- ** by <TD COLSPAN=N> markup where N>=2.
- */
- int colMin[HTML_MAX_COLUMNS+1][HTML_MAX_COLUMNS+1];
-# define ColMin(A,B) colMin[(A)-1][(B)-1]
-# define ColReq(A,B) colMin[(B)-1][(A)-1]
-
- if( pStart==0 || pStart->base.type!=Html_TABLE ){
- TestPoint(0);
- return pStart;
- }
- TRACE_PUSH(HtmlTrace_Table1);
- TRACE(HtmlTrace_Table1, ("Starting TableDimensions..\n"));
- pStart->table.nCol = 0;
- pStart->table.nRow = 0;
- z = HtmlMarkupArg(pStart, "border", 0);
- if( z && *z==0 ) z = "2";
- tbw = pStart->table.borderWidth = z ? atoi(z) : DFLT_BORDER;
- cbw = tbw>0;
- z = HtmlMarkupArg(pStart, "cellpadding", 0);
- cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
- cellSpacing = CellSpacing(htmlPtr, pStart);
-#ifdef DEBUG
- /* The HtmlTrace_Table4 flag causes tables to be draw with borders
- ** of 2, cellPadding of 5 and cell spacing of 2. This makes the
- ** table clearly visible. Useful for debugging. */
- if( HtmlTraceMask & HtmlTrace_Table4 ){
- tbw = pStart->table.borderWidth = 2;
- cbw = 1;
- cellPadding = 5;
- cellSpacing = 2;
- pStart->base.style.bgcolor = COLOR_Background;
- }
-#endif
- separation = cellSpacing + 2*(cellPadding + cbw);
- margin = tbw + cellSpacing + cbw + cellPadding;
- z = HtmlMarkupArg(pStart, "hspace", 0);
- hspace = z ? atoi(z) : DFLT_HSPACE;
-
- for(p=pStart->pNext; p && p->base.type!=Html_EndTABLE; p=pNext){
- pNext = p->pNext;
- switch( p->base.type ){
- case Html_EndTD:
- case Html_EndTH:
- case Html_EndTABLE:
- p->ref.pOther = pStart;
- TestPoint(0);
- break;
- case Html_EndTR:
- p->ref.pOther = pStart;
- inRow = 0;
- TestPoint(0);
- break;
- case Html_TR:
- p->ref.pOther = pStart;
- iRow++;
- pStart->table.nRow++;
- iCol = 0;
- inRow = 1;
- maxTableWidth = availWidth = lineWidth - 2*margin;
- TestPoint(0);
- break;
- case Html_CAPTION:
- while( p && p->base.type!=Html_EndTABLE
- && p->base.type!=Html_EndCAPTION ){
- p = p->pNext;
- TestPoint(0);
- }
- break;
- case Html_TD:
- case Html_TH:
- if( !inRow ){
- /* If the <TR> markup is omitted, insert it. */
- HtmlElement *pNew = HtmlAlloc( sizeof(HtmlRef) );
- if( pNew==0 ) break;
- memset(pNew, 0, sizeof(HtmlRef));
- pNew->base = p->base;
- pNew->base.pNext = p;
- pNew->base.type = Html_TR;
- pNew->base.count = 0;
- p->base.pPrev->base.pNext = pNew;
- p->base.pPrev = pNew;
- pNext = pNew;
- break;
- }
- do{
- iCol++;
- }while( iCol <= pStart->table.nCol && fromAbove[iCol] > iRow );
- p->cell.pTable = pStart;
- colspan = p->cell.colspan;
- if( colspan==0 ){
- colspan = 1;
- }
- if( iCol + colspan - 1 > pStart->table.nCol ){
- int nCol = iCol + colspan - 1;
- if( nCol > HTML_MAX_COLUMNS ){
- nCol = HTML_MAX_COLUMNS;
- }
- for(i=pStart->table.nCol+1; i<=nCol; i++){
- fromAbove[i] = 0;
- pStart->table.minW[i] = 0;
- pStart->table.maxW[i] = 0;
- min0span[i] = 0;
- max0span[i] = 0;
- reqW[i] = 0;
- for(j=1; j<i; j++){
- ColMin(j,i) = 0;
- ColReq(j,i) = 0;
- }
- }
- pStart->table.nCol = nCol;
- }
- noWrap = HtmlMarkupArg(p, "nowrap", 0)!=0;
- pNext = MinMax(htmlPtr, p, &minW, &maxW, availWidth);
- p->cell.pEnd = pNext;
- if( (z = HtmlMarkupArg(p, "width", 0))!=0 ){
- for(i=0; isdigit(z[i]); i++){}
- if( strcmp(z,"*")==0 ){
- requestedW = availWidth;
- }else if( z[i]==0 ){
- requestedW = atoi(z);
- }else if( z[i]=='%' ){
- /* requestedW = (atoi(z)*availWidth + 99)/100; */
- requestedW = (atoi(z)*maxTableWidth + 99)/100;
- }
- }else{
- requestedW = 0;
- }
- TRACE(HtmlTrace_Table1,
- ("Row %d Column %d: min=%d max=%d req=%d stop at %s\n",
- iRow,iCol,minW,maxW,requestedW, HtmlTokenName(p->cell.pEnd)));
- if( noWrap ){
- minW = maxW;
- }
- if( iCol + p->cell.colspan <= HTML_MAX_COLUMNS ){
- int min = 0;
- if( p->cell.colspan==0 ){
- SETMAX( min0span[iCol], minW );
- SETMAX( max0span[iCol], maxW );
- min = min0span[iCol] + separation;
- }else if( colspan==1 ){
- SETMAX( pStart->table.minW[iCol], minW );
- SETMAX( pStart->table.maxW[iCol], maxW );
- SETMAX( reqW[iCol], requestedW );
- min = pStart->table.minW[iCol] + separation;
- }else{
- int n = p->cell.colspan;
- SETMAX( ColMin(iCol,iCol+n-1), minW);
- SETMAX( ColReq(iCol,iCol+n-1), requestedW);
- min = minW + separation;
-#if 0
- maxW = (maxW + (n - 1)*(1-separation))/n;
- for(i=iCol; i<iCol + n && i<HTML_MAX_COLUMNS; i++){
- SETMAX( pStart->table.maxW[i], maxW );
- }
-#endif
- }
- availWidth -= min;
- }
- rowspan = p->cell.rowspan;
- if( rowspan==0 ){
- rowspan = LARGE_NUMBER;
- }
- if( rowspan>1 ){
- for(i=iCol; i<iCol + p->cell.colspan && i<HTML_MAX_COLUMNS; i++){
- fromAbove[i] = iRow + rowspan;
- }
- }
- if( p->cell.colspan > 1 ){
- iCol += p->cell.colspan - 1;
- }else if( p->cell.colspan==0 ){
- iCol = HTML_MAX_COLUMNS + 1;
- }
- break;
- }
- }
-
-#ifdef DEBUG
- if( HtmlTraceMask & HtmlTrace_Table6 ){
- char *zSpace = "";
- TRACE_INDENT;
- for(i=1; i<=pStart->table.nCol; i++){
- printf("%s%d:%d..%d",zSpace,i,
- pStart->table.minW[i],pStart->table.maxW[i]);
- if( reqW[i]>0 ){
- printf("(w=%d)",reqW[i]);
- }
- zSpace = " ";
- }
- printf("\n");
- for(i=1; i<pStart->table.nCol; i++){
- for(j=i+1; j<=pStart->table.nCol; j++){
- if( ColMin(i,j)>0 ){
- TRACE_INDENT;
- printf("ColMin(%d,%d) = %d\n", i, j, ColMin(i,j));
- }
- if( ColReq(i,j)>0 ){
- TRACE_INDENT;
- printf("ColReq(%d,%d) = %d\n", i, j, ColReq(i,j));
- }
- }
- }
- }
-#endif
-
- /* Compute the min and max width of each column
- */
- for(i=1; i<=pStart->table.nCol; i++){
- int sumMin, sumReq, sumMax;
-
- /* Reduce the max[] field to N for columns that have "width=N" */
- if( reqW[i]>0 ){
- pStart->table.maxW[i] = MAX(pStart->table.minW[i],reqW[i]);
- }
-
- /* Expand the width of columns marked with "colspan=0".
- */
- if( min0span[i]>0 || max0span[i]>0 ){
- int n = pStart->table.nCol - i + 1;
- minW = (min0span[i] + (n - 1)*(1-separation))/n;
- maxW = (max0span[i] + (n - 1)*(1-separation))/n;
- for(j=i; j<=pStart->table.nCol; j++){
- SETMAX( pStart->table.minW[j], minW );
- SETMAX( pStart->table.maxW[j], maxW );
- }
- }
-
- /* Expand the minW[] of columns to accomodate "colspan=N" constraints.
- ** The minW[] is expanded up to the maxW[] first. Then all the maxW[]s
- ** are expanded in proportion to their sizes. The same thing occurs
- ** for reqW[]s.
- */
- sumReq = reqW[i];
- sumMin = pStart->table.minW[i];
- sumMax = pStart->table.maxW[i];
- for(j=i-1; j>=1; j--){
- int cmin, creq;
- sumMin += pStart->table.minW[j];
- sumMax += pStart->table.maxW[j];
- sumReq += reqW[i];
- cmin = ColMin(j,i);
- if( cmin>sumMin ){
- int k;
- double scale;
- int *tminW = pStart->table.minW;
- int *tmaxW = pStart->table.maxW;
- if( sumMin<sumMax ){
- scale = (double)(cmin - sumMin)/(double)(sumMax - sumMin);
- for(k=j; k<=i; k++){
- sumMin -= tminW[k];
- tminW[k] = (tmaxW[k] - tminW[k])*scale + tminW[k];
- sumMin += tminW[k];
- }
- }else if( sumMin>0 ){
- scale = (double)cmin/(double)sumMin;
- for(k=j; k<=i; k++){
- sumMin -= tminW[k];
- tminW[k] = tmaxW[k] = tminW[k]*scale;
- sumMin += tminW[k];
- }
- }else{
- int unit = cmin/(i-j+1);
- for(k=j; k<=i; k++){
- tminW[k] = tmaxW[k] = unit;
- sumMin += tminW[k];
- }
- }
- }
- creq = ColReq(j,i);
- if( creq>sumReq ){
- int k;
- double scale;
- int *tmaxW = pStart->table.maxW;
- if( sumReq<sumMax ){
- scale = (double)(creq - sumReq)/(double)(sumMax - sumReq);
- for(k=j; k<=i; k++){
- sumReq -= reqW[k];
- reqW[k] = (tmaxW[k] - reqW[k])*scale + reqW[k];
- sumReq += reqW[k];
- }
- }else if( sumReq>0 ){
- scale = (double)creq/(double)sumReq;
- for(k=j; k<=i; k++){
- sumReq -= reqW[k];
- reqW[k] = reqW[k]*scale;
- sumReq += reqW[k];
- }
- }else{
- int unit = creq/(i-j+1);
- for(k=j; k<=i; k++){
- reqW[k] = unit;
- sumReq += reqW[k];
- }
- }
- }
- }
- }
-
-#ifdef DEBUG
- if( HtmlTraceMask & HtmlTrace_Table6 ){
- char *zSpace = "";
- TRACE_INDENT;
- for(i=1; i<=pStart->table.nCol; i++){
- printf("%s%d:%d..%d",zSpace,i,
- pStart->table.minW[i],pStart->table.maxW[i]);
- if( reqW[i]>0 ){
- printf("(w=%d)",reqW[i]);
- }
- zSpace = " ";
- }
- printf("\n");
- }
-#endif
-
- /* Compute the min and max width of the whole table
- */
- n = pStart->table.nCol;
- requestedW = tbw*2 + (n+1)*cellSpacing + n*2*(cellPadding + cbw);
- pStart->table.minW[0] = requestedW;
- pStart->table.maxW[0] = requestedW;
- for(i=1; i<=pStart->table.nCol; i++){
- pStart->table.minW[0] += pStart->table.minW[i];
- pStart->table.maxW[0] += pStart->table.maxW[i];
- requestedW += MAX(reqW[i], pStart->table.minW[i]);
- }
-
- /* Figure out how wide to draw the table */
- z = HtmlMarkupArg(pStart, "width", 0);
- if( z ){
- int len = strlen(z);
- int totalWidth;
- if( len>0 && z[len-1]=='%' ){
- totalWidth = (atoi(z) * lineWidth)/100;
- }else{
- totalWidth = atoi(z);
- }
- SETMAX( requestedW, totalWidth );
- }
- if( lineWidth && (requestedW > lineWidth) ){
- TRACE(HtmlTrace_Table5,("RequestedW reduced to lineWidth: %d -> %d\n",
- requestedW, lineWidth));
- requestedW = lineWidth;
- }
- if( requestedW > pStart->table.minW[0] ){
- float scale;
- int *tminW = pStart->table.minW;
- int *tmaxW = pStart->table.maxW;
- TRACE(HtmlTrace_Table5,
- ("Expanding table minW from %d to %d. (reqW=%d width=%s)\n",
- tminW[0], requestedW, requestedW, z));
- if( tmaxW[0] > tminW[0] ){
- scale = (double)(requestedW - tminW[0]) / (double)(tmaxW[0] - tminW[0]);
- for(i=1; i<=pStart->table.nCol; i++){
- tminW[i] += (tmaxW[i] - tminW[i]) * scale;
- SETMAX(tmaxW[i], tminW[i]);
- }
- }else if( tminW[0]>0 ){
- scale = requestedW/(double)tminW[0];
- for(i=1; i<=pStart->table.nCol; i++){
- tminW[i] *= scale;
- tmaxW[i] *= scale;
- }
- }else if( pStart->table.nCol>0 ){
- int unit = (requestedW - margin)/pStart->table.nCol - separation;
- if( unit<0 ) unit = 0;
- for(i=1; i<=pStart->table.nCol; i++){
- tminW[i] = tmaxW[i] = unit;
- }
- }else{
- tminW[0] = tmaxW[0] = requestedW;
- }
- pStart->table.minW[0] = requestedW;
- SETMAX( pStart->table.maxW[0], requestedW );
- }
-
-#ifdef DEBUG
- if( HtmlTraceMask & HtmlTrace_Table5 ){
- TRACE_INDENT;
- printf("Start with %s and ", HtmlTokenName(pStart));
- printf("end with %s\n", HtmlTokenName(p));
- TRACE_INDENT;
- printf("nCol=%d minWidth=%d maxWidth=%d\n",
- pStart->table.nCol, pStart->table.minW[0], pStart->table.maxW[0]);
- for(i=1; i<=pStart->table.nCol; i++){
- TRACE_INDENT;
- printf("Column %d minWidth=%d maxWidth=%d\n",
- i, pStart->table.minW[i], pStart->table.maxW[i]);
- }
- }
-#endif
-
- TRACE(HtmlTrace_Table1,
- ("Result of TableDimensions: min=%d max=%d nCol=%d\n",
- pStart->table.minW[0], pStart->table.maxW[0], pStart->table.nCol));
- TRACE_POP(HtmlTrace_Table1);
- return p;
-}
-
-/*
-** Given a list of elements, compute the minimum and maximum width needed
-** to render the list. Stop the search at the first element seen that is
-** in the following set:
-**
-** <tr> <td> <th> </tr> </td> </th> </table>
-**
-** Return a pointer to the element that stopped the search, or to NULL
-** if we ran out of data.
-**
-** Sometimes the value returned for both min and max will be larger than
-** the true minimum and maximum. This is rare, and only occurs if the
-** element string contains figures with flow-around text.
-*/
-static HtmlElement *MinMax(
- HtmlWidget *htmlPtr, /* The Html widget */
- HtmlElement *p, /* Start the search here */
- int *pMin, /* Return the minimum width here */
- int *pMax, /* Return the maximum width here */
- int lineWidth /* Total width available */
-){
- int min = 0; /* Minimum width so far */
- int max = 0; /* Maximum width so far */
- int indent = 0; /* Amount of indentation (minimum) */
- int obstacle = 0; /* Possible obstacles in the margin */
- int x1 = 0; /* Length of current line assuming maximum length */
- int x2 = 0; /* Length of current line assuming minimum length */
- int go = 1; /* Change to 0 to stop the loop */
- HtmlElement *pNext; /* Next element in the list */
-
- for(p=p->pNext; go && p; p = pNext){
- pNext = p->pNext;
- switch( p->base.type ){
- case Html_Text:
- x1 += p->text.w;
- x2 += p->text.w;
- if( p->base.style.flags & STY_Preformatted ){
- SETMAX( min, x1 );
- SETMAX( max, x1 );
- }else{
- SETMAX( min, x2 );
- SETMAX( max, x1 );
- }
- break;
- case Html_Space:
- if( p->base.style.flags & STY_Preformatted ){
- if( p->base.flags & HTML_NewLine ){
- x1 = x2 = indent;
- }else{
- x1 += p->space.w * p->base.count;
- x2 += p->space.w * p->base.count;
- }
- }else if( p->base.style.flags & STY_NoBreak ){
- if( x1>indent ){ x1 += p->space.w; TestPoint(0);}
- if( x2>indent ){ x2 += p->space.w; TestPoint(0);}
- }else{
- if( x1>indent ){ x1 += p->space.w; TestPoint(0);}
- x2 = indent;
- }
- break;
- case Html_IMG:
- switch( p->image.align ){
- case IMAGE_ALIGN_Left:
- case IMAGE_ALIGN_Right:
- obstacle += p->image.w;
- x1 = obstacle + indent;
- x2 = indent;
- SETMAX( min, x2 );
- SETMAX( min, p->image.w );
- SETMAX( max, x1 );
- break;
- default:
- x1 += p->image.w;
- x2 += p->image.w;
- if( p->base.style.flags & STY_Preformatted ){
- SETMAX( min, x1 );
- SETMAX( max, x1 );
- }else{
- SETMAX( min, x2 );
- SETMAX( max, x1 );
- }
- break;
- }
- break;
- case Html_TABLE:
- /* pNext = TableDimensions(htmlPtr, p, lineWidth-indent); */
- pNext = TableDimensions(htmlPtr, p, 0);
- x1 = p->table.maxW[0] + indent + obstacle;
- x2 = p->table.minW[0] + indent;
- SETMAX( max, x1 );
- SETMAX( min, x2 );
- x1 = indent + obstacle;
- x2 = indent;
- if( pNext && pNext->base.type==Html_EndTABLE ){
- pNext = pNext->pNext;
- }
- break;
- case Html_UL:
- case Html_OL:
- indent += HTML_INDENT;
- x1 = indent + obstacle;
- x2 = indent;
- break;
- case Html_EndUL:
- case Html_EndOL:
- indent -= HTML_INDENT;
- if( indent < 0 ){ indent = 0; }
- x1 = indent + obstacle;
- x2 = indent;
- break;
- case Html_BLOCKQUOTE:
- indent += 2*HTML_INDENT;
- x1 = indent + obstacle;
- x2 = indent;
- break;
- case Html_EndBLOCKQUOTE:
- indent -= 2*HTML_INDENT;
- if( indent < 0 ){ indent = 0; }
- x1 = indent + obstacle;
- x2 = indent;
- break;
- case Html_APPLET:
- case Html_INPUT:
- case Html_SELECT:
- case Html_EMBED:
- case Html_TEXTAREA:
- x1 += p->input.w + p->input.padLeft;
- if( p->base.style.flags & STY_Preformatted ){
- SETMAX( min, x1 );
- SETMAX( max, x1 );
- x2 += p->input.w + p->input.padLeft;
- }else{
- SETMAX( min, indent + p->input.w );
- SETMAX( max, x1 );
- x2 = indent;
- }
- break;
- case Html_BR:
- case Html_P:
- case Html_EndP:
- case Html_DIV:
- case Html_EndDIV:
- case Html_H1:
- case Html_EndH1:
- case Html_H2:
- case Html_EndH2:
- case Html_H3:
- case Html_EndH3:
- case Html_H4:
- case Html_EndH4:
- case Html_H5:
- case Html_H6:
- x1 = indent + obstacle;
- x2 = indent;
- break;
- case Html_EndTD:
- case Html_EndTH:
- case Html_CAPTION:
- case Html_EndTABLE:
- case Html_TD:
- case Html_TR:
- case Html_TH:
- case Html_EndTR:
- go = 0;
- break;
- default:
- break;
- }
- if( !go ){ break; }
- }
- *pMin = min;
- *pMax = max;
- return p;
-}
-
-/* Vertical alignments:
-*/
-#define VAlign_Unknown 0
-#define VAlign_Top 1
-#define VAlign_Bottom 2
-#define VAlign_Center 3
-#define VAlign_Baseline 4
-
-/*
-** Return the vertical alignment specified by the given element.
-*/
-static int GetVerticalAlignment(HtmlElement *p, int dflt){
- char *z;
- int rc;
- if( p==0 ) return dflt;
- z = HtmlMarkupArg(p, "valign", 0);
- if( z==0 ){
- rc = dflt;
- TestPoint(0);
- }else if( stricmp(z,"top")==0 ){
- rc = VAlign_Top;
- TestPoint(0);
- }else if( stricmp(z,"bottom")==0 ){
- rc = VAlign_Bottom;
- TestPoint(0);
- }else if( stricmp(z,"center")==0 ){
- rc = VAlign_Center;
- TestPoint(0);
- }else if( stricmp(z,"baseline")==0 ){
- rc = VAlign_Baseline;
- TestPoint(0);
- }else{
- rc = dflt;
- TestPoint(0);
- }
- return rc;
-}
-
-/* Do all layout for a single table. Return the </table> element or
-** NULL if the table is unterminated.
-*/
-HtmlElement *HtmlTableLayout(
- HtmlLayoutContext *pLC, /* The layout context */
- HtmlElement *pTable /* The <table> element */
-){
- HtmlElement *pEnd; /* The </table> element */
- HtmlElement *p; /* For looping thru elements of the table */
- HtmlElement *pNext; /* Next element in the loop */
- HtmlElement *pCaption; /* Start of the caption text. The <caption> */
- HtmlElement *pEndCaption; /* End of the caption. The </caption> */
- int width; /* Width of the table as drawn */
- int cellSpacing; /* Value of cellspacing= parameter to <table> */
- int cellPadding; /* Value of cellpadding= parameter to <table> */
- int tbw; /* Width of the 3D border around the whole table */
- int cbw; /* Width of the 3D border around a cell */
- int pad; /* cellPadding + borderwidth */
- char *z; /* A string */
- int leftMargin; /* The left edge of space available for drawing */
- int lineWidth; /* Total horizontal space available for drawing */
- int separation; /* Distance between content of columns (or rows) */
- int i; /* Loop counter */
- int n; /* Number of columns */
- int btm; /* Bottom edge of previous row */
- int iRow; /* Current row number */
- int iCol; /* Current column number */
- int colspan; /* Number of columns spanned by current cell */
- int vspace; /* Value of the vspace= parameter to <table> */
- int hspace; /* Value of the hspace= parameter to <table> */
- int rowBottom; /* Bottom edge of content in the current row */
- int defaultVAlign; /* Default vertical alignment for the current row */
- char *zAlign; /* Value of the ALIGN= attribute of the <TABLE> */
-#define N HTML_MAX_COLUMNS+1
- int y[N]; /* Top edge of each cell's content */
- int x[N]; /* Left edge of each cell's content */
- int w[N]; /* Width of each cell's content */
- int ymax[N]; /* Bottom edge of cell's content if valign=top */
- HtmlElement *apElem[N]; /* The <td> or <th> for each cell in a row */
- int firstRow[N]; /* First row on which a cell appears */
- int lastRow[N]; /* Row to which each cell span's */
- int valign[N]; /* Vertical alignment for each cell */
- HtmlLayoutContext savedContext; /* Saved copy of the original pLC */
- HtmlLayoutContext cellContext; /* Used to render a single cell */
-#ifdef TABLE_TRIM_BLANK
- extern int HtmlLineWasBlank;
-#endif /* TABLE_TRIM_BLANK */
-
- if( pTable==0 || pTable->base.type!=Html_TABLE ){
- TestPoint(0);
- return pTable;
- }
- TRACE_PUSH(HtmlTrace_Table2);
- TRACE(HtmlTrace_Table2, ("Starting TableLayout() at %s\n",
- HtmlTokenName(pTable)));
-
- /* Figure how much horizontal space is available for rendering
- ** this table. Store the answer in lineWidth. leftMargin is
- ** the left-most X coordinate of the table. btm stores the top-most
- ** Y coordinate.
- */
- HtmlComputeMargins(pLC, &leftMargin, &btm, &lineWidth);
- TRACE(HtmlTrace_Table2, ("...btm=%d left=%d width=%d\n",
- btm, leftMargin, lineWidth));
-
- /* figure out how much space the table wants for each column,
- ** and in total.. */
- pEnd = TableDimensions(pLC->htmlPtr, pTable, lineWidth);
-
- /* If we don't have enough horizontal space to accomodate the minimum table
- ** width, then try to move down past some obstruction (such as an
- ** <IMG ALIGN=LEFT>) to give us more room.
- */
- if( lineWidth < pTable->table.minW[0] ){
- HtmlWidenLine(pLC, pTable->table.minW[0], &leftMargin, &btm, &lineWidth);
- TRACE(HtmlTrace_Table2, ("Widen to btm=%d left=%d width=%d\n",
- btm, leftMargin, lineWidth));
- }
- savedContext = *pLC;
-
- /* Figure out how wide to draw the table
- */
- if( lineWidth < pTable->table.minW[0] ){
- width = pTable->table.minW[0];
- }else if( lineWidth <= pTable->table.maxW[0] ){
- width = lineWidth;
- }else{
- width = pTable->table.maxW[0];
- }
-
-
- /* Compute the width and left edge position of every column in
- ** the table */
- z = HtmlMarkupArg(pTable, "cellpadding", 0);
- cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
- cellSpacing = CellSpacing(pLC->htmlPtr, pTable);
- z = HtmlMarkupArg(pTable, "vspace", 0);
- vspace = z ? atoi(z) : DFLT_VSPACE;
- z = HtmlMarkupArg(pTable, "hspace", 0);
- hspace = z ? atoi(z) : DFLT_HSPACE;
-#ifdef DEBUG
- if( HtmlTraceMask & HtmlTrace_Table4 ){
- cellPadding = 5;
- cellSpacing = 2;
- if( vspace<2 ) vspace = 2;
- if( hspace<2 ) hspace = 2;
- }
-#endif
- tbw = pTable->table.borderWidth;
- cbw = (tbw>0);
- pad = cellPadding + cbw;
- separation = cellSpacing + 2*pad;
- x[1] = leftMargin + tbw + cellSpacing + pad;
- n = pTable->table.nCol;
- if( n<=0 || pTable->table.maxW[0]<=0 ){
- /* Abort if the table has no columns at all or if the total width
- ** of the table is zero or less. */
- return pEnd;
- }
- zAlign = HtmlMarkupArg(pTable, "align", "");
- if( width < lineWidth ){
- int align = pTable->base.style.align;
- if( align==ALIGN_Right || stricmp(zAlign,"right")==0 ){
- x[1] += lineWidth - width;
- }else if( align==ALIGN_Center && stricmp(zAlign,"left")!=0 ){
- x[1] += (lineWidth - width)/2;
- }
- }
- if( width==pTable->table.maxW[0] ){
- w[1] = pTable->table.maxW[1];
- for(i=2; i<=n; i++){
- w[i] = pTable->table.maxW[i];
- x[i] = x[i-1] + w[i-1] + separation;
- TestPoint(0);
- }
- }else if( width > pTable->table.maxW[0] ){
- int *tmaxW = pTable->table.maxW;
- double scale = ((double)width)/ (double)tmaxW[0];
- w[1] = tmaxW[1] * scale;
- for(i=2; i<=n; i++){
- w[i] = tmaxW[i] * scale;
- x[i] = x[i-1] + w[i-1] + separation;
- TestPoint(0);
- }
- }else if( width > pTable->table.minW[0] ){
- float scale;
- int *tminW = pTable->table.minW;
- int *tmaxW = pTable->table.maxW;
- scale = (double)(width - tminW[0]) / (double)(tmaxW[0] - tminW[0]);
- w[1] = tminW[1] + (tmaxW[1] - tminW[1]) * scale;
- for(i=2; i<=n; i++){
- w[i] = tminW[i] + (tmaxW[i] - tminW[i]) * scale;
- x[i] = x[i-1] + w[i-1] + separation;
- TestPoint(0);
- }
- }else{
- w[1] = pTable->table.minW[1];
- for(i=2; i<=n; i++){
- w[i] = pTable->table.minW[i];
- x[i] = x[i-1] + w[i-1] + separation;
- TestPoint(0);
- }
- }
- w[n] = width - ((x[n] - x[1]) + 2*(tbw + pad + cellSpacing));
-
- /* Add notation to the pTable structure so that we will know where
- ** to draw the outer box around the outside of the table.
- */
- btm += vspace;
- pTable->table.y = btm;
- pTable->table.x = x[1] - (tbw + cellSpacing + pad);
- pTable->table.w = width;
- SETMAX(pLC->maxX, pTable->table.x + pTable->table.w);
- btm += tbw + cellSpacing;
-
- /* Begin rendering rows of the table */
- for(i=1; i<=n; i++){
- firstRow[i] = 0;
- lastRow[i] = 0;
- apElem[i] = 0;
- }
- p = pTable->pNext;
- rowBottom = btm;
- for(iRow=1; iRow<=pTable->table.nRow; iRow++){
- TRACE(HtmlTrace_Table2, ("Row %d: btm=%d\n",iRow,btm));
- /* Find the start of the next row. Keep an eye out for the caption
- ** while we search */
- while( p && p->base.type!=Html_TR ){
- if( p->base.type==Html_CAPTION ){
- pCaption = p;
- while( p && p!=pEnd && p->base.type!=Html_EndCAPTION ){
- p = p->pNext;
- }
- pEndCaption = p;
- }
- TRACE(HtmlTrace_Table3, ("Skipping token %s\n", HtmlTokenName(p)));
- p = p->pNext;
- }
- if( p==0 ){ TestPoint(0); break; }
-
- /* Record default vertical alignment flag for this row */
- defaultVAlign = GetVerticalAlignment(p, VAlign_Center);
-
- /* Find every new cell on this row */
- for(iCol=1; iCol<=pTable->table.nCol && iCol<HTML_MAX_COLUMNS; iCol++){
- if( lastRow[iCol]<iRow ) ymax[iCol] = 0;
- }
- iCol = 0;
- for(p=p->pNext; p && p->base.type!=Html_TR && p!=pEnd; p=pNext){
- pNext = p->pNext;
- TRACE(HtmlTrace_Table3, ("Processing token %s\n", HtmlTokenName(p)));
- switch( p->base.type ){
- case Html_TD:
- case Html_TH:
- /* Find the column number for this cell. Be careful to skip
- ** columns which extend down to this row from prior rows */
- do{
- iCol++;
- }while( iCol <= HTML_MAX_COLUMNS && lastRow[iCol] >= iRow );
- TRACE(HtmlTrace_Table2,
- ("Column %d: x=%d w=%d\n",iCol,x[iCol],w[iCol]));
- /* Process the new cell. (Cells beyond the maximum number of
- ** cells are simply ignored.) */
- if( iCol <= HTML_MAX_COLUMNS ){
- apElem[iCol] = p;
- pNext = p->cell.pEnd;
- if( p->cell.rowspan==0 ){
- lastRow[iCol] = pTable->table.nRow;
- }else{
- lastRow[iCol] = iRow + p->cell.rowspan - 1;
- }
- firstRow[iCol] = iRow;
-
- /* Set vertical alignment flag for this cell */
- valign[iCol] = GetVerticalAlignment(p, defaultVAlign);
-
- /* Render cell contents and record the height */
- y[iCol] = btm + pad;
- cellContext.htmlPtr = pLC->htmlPtr;
- cellContext.pStart = p->pNext;
- cellContext.pEnd = pNext;
- cellContext.headRoom = 0;
- cellContext.top = y[iCol];
- cellContext.bottom = y[iCol];
- cellContext.left = x[iCol];
- cellContext.right = 0;
- cellContext.pageWidth = x[iCol]+w[iCol];
- colspan = p->cell.colspan;
- if( colspan==0 ){
- for(i=iCol+1; i<=pTable->table.nCol; i++){
- cellContext.pageWidth += w[i] + separation;
- lastRow[i] = lastRow[iCol];
- }
- }else if( colspan>1 ){
- for(i=iCol+1; i<iCol+colspan; i++){
- cellContext.pageWidth += w[i] + separation;
- lastRow[i] = lastRow[iCol];
- }
- }
- cellContext.maxX = 0;
- cellContext.maxY = 0;
- cellContext.leftMargin = 0;
- cellContext.rightMargin = 0;
- HtmlLock(cellContext.htmlPtr);
- HtmlLayoutBlock(&cellContext);
- if( HtmlUnlock(cellContext.htmlPtr) ) return 0;
-#ifdef TABLE_TRIM_BLANK
- /*
- * Cancel any trailing vertical whitespace caused
- * by break markup
- */
- if (HtmlLineWasBlank)
- cellContext.maxY -= cellContext.headRoom;
-#endif /* TABLE_TRIM_BLANK */
- ymax[iCol] = cellContext.maxY;
- SETMAX(ymax[iCol], y[iCol]);
- HtmlClearMarginStack(&cellContext.leftMargin);
- HtmlClearMarginStack(&cellContext.rightMargin);
-
- /* Set coordinates of the cell border */
- p->cell.x = x[iCol] - pad;
- p->cell.y = btm;
- p->cell.w = cellContext.pageWidth + 2*pad - x[iCol];
- TRACE(HtmlTrace_Table2,
- ("Column %d top=%d bottom=%d h=%d left=%d w=%d\n",
- iCol, y[iCol], ymax[iCol], ymax[iCol]-y[iCol],
- p->cell.x, p->cell.w));
-
- /* Advance the column counter for cells spaning multiple columns */
- if( colspan > 1 ){
- iCol += colspan - 1;
- }else if( colspan==0 ){
- iCol = HTML_MAX_COLUMNS + 1;
- }
- }
- break;
-
- case Html_CAPTION:
- /* Gotta remember where the caption is so we can render it
- ** at the end */
- pCaption = p;
- while( pNext && pNext!=pEnd && pNext->base.type!=Html_EndCAPTION ){
- pNext = pNext->pNext;
- }
- pEndCaption = pNext;
- break;
- }
- }
-
- /* Figure out how high to make this row. */
- for(iCol=1; iCol<=pTable->table.nCol; iCol++){
- if( lastRow[iCol] == iRow || iRow==pTable->table.nRow ){
- SETMAX( rowBottom, ymax[iCol] );
- }
- }
- TRACE(HtmlTrace_Table2, ("Total row height: %d..%d -> %d\n",
- btm,rowBottom,rowBottom-btm));
-
- /* Position every cell whose bottom edge ends on this row */
- for(iCol=1; iCol<=pTable->table.nCol; iCol++){
- int dy; /* Extra space at top of cell used for vertical alignment */
-
- /* Skip any unused cells or cells that extend down thru
- ** subsequent rows */
- if( apElem[iCol]==0
- || (iRow!=pTable->table.nRow && lastRow[iCol]>iRow) ){ continue; }
-
- /* Align the contents of the cell vertically. */
- switch( valign[iCol] ){
- case VAlign_Unknown:
- case VAlign_Center:
- dy = (rowBottom - ymax[iCol])/2;
- break;
- case VAlign_Top:
- case VAlign_Baseline:
- dy = 0;
- break;
- case VAlign_Bottom:
- dy = rowBottom - ymax[iCol];
- break;
- }
- if( dy ){
- HtmlElement *pLast = apElem[iCol]->cell.pEnd;
- TRACE(HtmlTrace_Table3, ("Delta column %d by %d\n",iCol,dy));
- HtmlMoveVertically(apElem[iCol]->pNext, pLast, dy);
- }
-
- /* Record the height of the cell so that the border can be drawn */
- apElem[iCol]->cell.h = rowBottom + pad - apElem[iCol]->cell.y;
- apElem[iCol] = 0;
- }
-
- /* Update btm to the height of the row we just finished setting */
- btm = rowBottom + pad + cellSpacing;
- }
-
- btm += tbw;
- pTable->table.h = btm - pTable->table.y;
- SETMAX( pLC->maxY, btm );
- pLC->bottom = btm + vspace;
-
- /* Render the caption, if there is one */
- if( pCaption ){
- }
-
- /* Whenever we do any table layout, we need to recompute all the
- ** HtmlBlocks. The following statement forces this. */
- pLC->htmlPtr->firstBlock = pLC->htmlPtr->lastBlock = 0;
-
- /* Adjust the context for text that wraps around the table, if
- ** requested by an ALIGN=RIGHT or ALIGN=LEFT attribute.
- */
- if( stricmp(zAlign,"left")==0 ){
- savedContext.maxX = pLC->maxX;
- savedContext.maxY = pLC->maxY;
- *pLC = savedContext;
- HtmlPushMargin(&pLC->leftMargin, pTable->table.w + 2,
- pTable->table.y + pTable->table.h + 2, 0);
- }else if( stricmp(zAlign,"right")==0 ){
- savedContext.maxX = pLC->maxX;
- savedContext.maxY = pLC->maxY;
- *pLC = savedContext;
- HtmlPushMargin(&pLC->rightMargin, pTable->table.w + 2,
- pTable->table.y + pTable->table.h + 2, 0);
- }
-
- /* All done */
- TRACE(HtmlTrace_Table2, (
- "Done with TableLayout(). x=%d y=%d w=%d h=%d Return %s\n",
- pTable->table.x, pTable->table.y, pTable->table.w, pTable->table.h,
- HtmlTokenName(pEnd)));
- TRACE_POP(HtmlTrace_Table2);
- return pEnd;
-}
-
-
-/*
-** Move all elements in the given list vertically by the amount dy
-*/
-void HtmlMoveVertically(
- HtmlElement *p, /* First element to move */
- HtmlElement *pLast, /* Last element. Do move this one */
- int dy /* Amount by which to move */
-){
- if( dy==0 ){ TestPoint(0); return; }
- while( p && p!=pLast ){
- switch( p->base.type ){
- case Html_A:
- p->anchor.y += dy;
- break;
- case Html_Text:
- p->text.y += dy;
- break;
- case Html_LI:
- p->li.y += dy;
- break;
- case Html_TD:
- case Html_TH:
- p->cell.y += dy;
- break;
- case Html_TABLE:
- p->table.y += dy;
- break;
- case Html_IMG:
- p->image.y += dy;
- break;
- case Html_INPUT:
- case Html_SELECT:
- case Html_APPLET:
- case Html_EMBED:
- case Html_TEXTAREA:
- p->input.y += dy;
- break;
- default:
- break;
- }
- p = p->pNext;
- }
-}