TGHtmlTable.cxx

Go to the documentation of this file.
00001 // $Id: TGHtmlTable.cxx,v 1.1 2007/05/04 17:07:01 brun Exp $
00002 // Author:  Valeriy Onuchin   03/05/2007
00003 
00004 /**************************************************************************
00005 
00006     HTML widget for xclass. Based on tkhtml 1.28
00007     Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
00008     Copyright (C) 2002-2003 Hector Peraza.
00009 
00010     This library is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU Library General Public
00012     License as published by the Free Software Foundation; either
00013     version 2 of the License, or (at your option) any later version.
00014 
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Library General Public License for more details.
00019 
00020     You should have received a copy of the GNU Library General Public
00021     License along with this library; if not, write to the Free
00022     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023 
00024 **************************************************************************/
00025 
00026 // Routines for doing layout of HTML tables
00027 
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <math.h>
00032 
00033 #include "TGHtml.h"
00034 
00035 
00036 // Default values for various table style parameters
00037 
00038 #define DFLT_BORDER             0
00039 #define DFLT_CELLSPACING_3D     5
00040 #define DFLT_CELLSPACING_FLAT   0
00041 #define DFLT_CELLPADDING        2
00042 #define DFLT_HSPACE             0
00043 #define DFLT_VSPACE             0
00044 
00045 // Set parameter A to the maximum of A and B.
00046 #define SETMAX(A,B)  if ((A) < (B)) { (A) = (B); }
00047 #define MAX(A,B)     ((A) < (B) ? (B) : (A))
00048 
00049 
00050 //______________________________________________________________________________
00051 int TGHtml::CellSpacing(TGHtmlElement *pTable)
00052 {
00053    // Return the appropriate cell spacing for the given table.
00054 
00055    const char *z;
00056    int relief;
00057    int cellSpacing;
00058 
00059    z = pTable->MarkupArg("cellspacing", 0);
00060    if (z == 0) {
00061       relief = fTableRelief;
00062       if (relief == HTML_RELIEF_RAISED || relief == HTML_RELIEF_SUNKEN) {
00063          cellSpacing = DFLT_CELLSPACING_3D;
00064       } else {
00065          cellSpacing = DFLT_CELLSPACING_FLAT;
00066       }
00067    } else {
00068       cellSpacing = atoi(z);
00069    }
00070 
00071    return cellSpacing;
00072 }
00073 
00074 //______________________________________________________________________________
00075 void TGHtml::StringHW(const char *str, int *h, int *w)
00076 {
00077    // Return the height and width of string.
00078 
00079    const char *cp = str;
00080    int nw = 0, nh = 1, mw = 0;
00081    *h = 0; *w =0;
00082 
00083    if (!cp) return;
00084 
00085    while (*cp) {
00086       if (*cp != '\n') {
00087          nw++;
00088       } else {
00089          if (nw > mw) mw = nw;
00090          nw = 0;
00091          nh++;
00092       }
00093       cp++;
00094    }
00095    if (nw > mw) mw = nw;
00096    *w = mw;
00097    *h = nh;
00098 }
00099 
00100 //______________________________________________________________________________
00101 TGString *TGHtml::TableText(TGHtmlTable *pTable, int flag)
00102 {
00103    // Return text and images from a table as lists.
00104    // The first list is a list of rows (which is a list of cells).
00105    // An optional second list is a list of images: row col charoffset tokenid.
00106    // Note: weve added the option to store data/attrs in array var directly.
00107    //
00108    // flag - include images
00109 
00110    int j, h, w,
00111       nest = 0,
00112  //     intext = 0,
00113       rows = 0,
00114       cols = 0,
00115       numcols = 0,
00116       maxh = 1;
00117    int cspans = 0,
00118       rspanstart = 0,
00119       images = flag & 1,
00120       attrs = flag & 2;
00121    unsigned short maxw[HTML_MAX_COLUMNS];
00122    short rspans[HTML_MAX_COLUMNS];
00123    char buf[100];
00124    const char *cp;
00125    TGHtmlElement *p, *pEnd;
00126    TGString istr("");     // Information string
00127    TGString substr("");   // Temp to collect current cell string.
00128    TGString imgstr("");   // Image information
00129    TGString attrstr("");  // Attribue information
00130 
00131    TGString *str = new TGString("");  // The result
00132 
00133    if (pTable->fType != Html_TABLE) return str;
00134    if (!(pEnd = pTable->fPEnd)) {
00135       delete str;
00136       return 0;
00137    }
00138 
00139    str->Append("{ ");  // start sublist
00140    if (attrs) {
00141       attrstr.Append("{ ");  // start sublist
00142       AppendArglist(&attrstr, pTable);
00143       attrstr.Append("} ");  // end sublist
00144    }
00145    for (j = 0; j < HTML_MAX_COLUMNS; j++) {
00146       maxw[j] = 0;
00147       rspans[j] = 0;
00148    }
00149    nest = 1;
00150    istr.Append("{ ");
00151    p = pTable;
00152    while (p && (p = p->fPNext)) {
00153       if (attrs) {
00154          switch (p->fType) {
00155             case Html_EndTR:
00156                break;
00157 
00158             case Html_TR:
00159                break;
00160          }
00161       }
00162 
00163       switch (p->fType) {
00164          case Html_TABLE:
00165             if (!(p = FindEndNest(p, Html_EndTABLE, 0))) {
00166                delete str;
00167                return 0;
00168             }
00169             break;
00170 
00171          case Html_EndTABLE:
00172             p = 0;
00173             break;
00174 
00175          case Html_TR:
00176             if (cols > numcols) numcols = cols;
00177             maxh = 1;
00178             cols = 0;
00179             rows++;
00180             nest++;
00181             str->Append("{ ");
00182             if (attrs) {
00183                attrstr.Append("{ { ");
00184                AppendArglist(&attrstr, (TGHtmlMarkupElement *) p);
00185                attrstr.Append("} ");
00186             }
00187             break;
00188 
00189          case Html_EndTR:
00190             snprintf(buf, 100, "%d ", maxh);
00191             istr.Append(buf);
00192             if (attrs) {
00193                attrstr.Append("} ");
00194             }
00195             while (nest > 1) {
00196                nest--;
00197                str->Append("} ");
00198             }
00199             break;
00200 
00201          case Html_TD:
00202          case Html_TH:
00203             if ((!(cp = p->MarkupArg("colspan", 0))) || (cspans = atoi(cp)) <= 0) {
00204                cspans = 1;
00205             }
00206             if ((cp = p->MarkupArg("rowspan", 0)) && (j = atoi(cp)) > 0 &&
00207                 cols < HTML_MAX_COLUMNS) {
00208                rspans[cols] = j;
00209                rspanstart = 1;
00210             } else {
00211                rspanstart = 0;
00212             }
00213             if (attrs) {
00214                j = 0;
00215                while ((cspans - j) > 0) {
00216                   attrstr.Append("{ ");
00217                   if (!j) AppendArglist(&attrstr, (TGHtmlMarkupElement *) p);
00218                   attrstr.Append("} ");
00219                   j++;
00220                }
00221             }
00222             cols++;
00223             substr = "";
00224             break;
00225 
00226          case Html_EndTD:
00227          case Html_EndTH:
00228             if (!rspanstart) {
00229                while (cols <= HTML_MAX_COLUMNS && rspans[cols-1]-- > 1) {
00230                   str->Append(" ");  // (""); ??
00231                   cols++;
00232                }
00233             }
00234             cp = substr.GetString();
00235 
00236             j = 0;
00237             while ((cspans - j) > 0) {
00238                str->Append(cp);
00239                str->Append(" ");
00240                if (!j) {
00241                   StringHW(cp, &h, &w);
00242                   if (h > maxh) maxh = h;
00243                   if (cols > 0 && cols <= HTML_MAX_COLUMNS) {
00244                      if (w > maxw[cols-1]) {
00245                         maxw[cols-1] = w;
00246                      }
00247                   }
00248                }
00249                j++;
00250                cp = "";
00251             }
00252             cspans = 0;
00253             break;
00254 
00255          case Html_Text:
00256             substr.Append(((TGHtmlTextElement *)p)->fZText, -1);
00257             break;
00258 
00259          case Html_Space:
00260             for (j = 0; j < p->fCount; j++) {
00261                substr.Append(" ");
00262             }
00263 //        if ((p->flag & HTML_NewLine) != 0)
00264 //          substr.Append("\n");
00265             break;
00266 
00267          case Html_BR:
00268             substr.Append("\n");  // ("\\n"); ??
00269             break;
00270 
00271          case Html_CAPTION:  // Should do something with Caption?
00272             if (!(pEnd = FindEndNest(p, Html_EndCAPTION, 0))) {
00273                p = pEnd;
00274             }
00275             break;
00276 
00277          case Html_IMG:  // Images return: row col charoffset tokenid
00278             if (!images) break;
00279             snprintf(buf, sizeof(buf), "%d %d %d %d ", rows-1, cols-1,
00280                      substr.GetLength(), p->fElId);
00281             imgstr.Append(buf);
00282             break;
00283       }
00284    }
00285 
00286    while (nest--) str->Append("} ");
00287    istr.Append("} { ");
00288    for (j = 0; j < numcols && j < HTML_MAX_COLUMNS; j++) {
00289       snprintf(buf, sizeof(buf), "%d ", maxw[j]);
00290       istr.Append(buf);
00291    }
00292    istr.Append("} ");
00293 
00294    str->Append(istr.Data());
00295    str->Append(" ");
00296    if (attrs) {
00297       str->Append("{ ");
00298       str->Append(attrstr.Data());
00299       str->Append("} ");
00300    }
00301    if (images) {
00302       str->Append(imgstr.Data());
00303    }
00304 
00305    return str;
00306 }
00307 
00308 //______________________________________________________________________________
00309 TGHtmlElement *TGHtml::FindEndNest(TGHtmlElement *sp, int en,
00310                                   TGHtmlElement *lp)
00311 {
00312    // Find End tag en, but ignore intervening begin/end tag pairs.
00313    //
00314    // sp -- Pointer to start from
00315    // en -- End tag to search for
00316    // lp -- Last pointer to try
00317 
00318    TGHtmlElement *p;
00319    int lvl, n;
00320 
00321    p = sp->fPNext;
00322    lvl = 0;
00323    n = sp->fType;
00324 
00325    while (p) {
00326       if (p == lp) return 0;
00327       if (n == Html_LI) {
00328          if (p->fType == Html_LI || p->fType == Html_EndUL ||
00329              p->fType == Html_EndOL) {
00330             if (p->fPPrev) return p->fPPrev;
00331             return p;
00332          }
00333       } else if (p->fType == n) {
00334          if (n == Html_OPTION) {
00335             if (p->fPPrev) return p->fPPrev;
00336             return p;
00337          }
00338          lvl++;
00339       } else if (p->fType == en) {
00340          if (!lvl--) return p;
00341       }
00342       switch (p->fType) {
00343          case Html_TABLE: p = ((TGHtmlTable *)p)->fPEnd; break; // optimization
00344          case Html_FORM:  p = ((TGHtmlForm *)p)->fPEnd;  break;
00345          default: p = p->fPNext;
00346       }
00347    }
00348 
00349    return 0;
00350 }
00351 
00352 //______________________________________________________________________________
00353 TGHtmlElement *TGHtml::TableDimensions(TGHtmlTable *pStart, int lineWidth)
00354 {
00355    // pStart points to a <table>.  Compute the number of columns, the
00356    // minimum and maximum size for each column and the overall minimum
00357    // and maximum size for this table and store these value in the
00358    // pStart structure.  Return a pointer to the </table> element,
00359    // or to NULL if there is no </table>.
00360    //
00361    // The min and max size for column N (where the leftmost column has
00362    // N==1) is pStart->fMinW[1] and pStart->fMaxW[1].  The pStart->fMinW[0]
00363    // and pStart->fMaxW[0] entries contain the minimum and maximum widths
00364    // of the whole table, including any cell padding, cell spacing,
00365    // border width and "hspace".  The values of pStart->fMinW[I] for I>=1
00366    // do not contain any cell padding, cell spacing or border width.
00367    // Only pStart->fMinW[0] contains these extra spaces.
00368    //
00369    // The back references from </table>, </tr>, </td> and </th> back to
00370    // the <table> markup are also filled in.  And for each <td> and <th>
00371    // markup, the pTable and pEnd fields are set to their proper values.
00372    //
00373    // pStart    - The <table> markup
00374    // lineWidth - Total width available to the table
00375 
00376    TGHtmlElement *p;                  // Element being processed
00377    TGHtmlElement *fPNext;              // Next element to process
00378    int iCol1 = 0;                     // Current column number.  1..N
00379    int iRow = 0;                      // Current row number
00380    TGHtmlElement *inRow = 0;          // Pointer to <TR>
00381    TGHtmlElement *inCol = 0;          // Pointer to <TD>
00382    int i, j;                          // Loop counters
00383    int n;                             // Number of columns
00384    int minW, maxW, requestedW;        // min, max, requested width for a cell
00385    int noWrap;                        // true for NOWRAP cells
00386    int colspan;                       // Column span for the current cell
00387    int rowspan;                       // Row span for the current cell
00388    const char *z;                     // Value of a <table> parameter
00389    int cellSpacing;                   // Value of CELLSPACING parameter
00390    int cellPadding;                   // Value of CELLPADDING parameter
00391    int tbw;                           // Width of border around whole table
00392    int cbw;                           // Width of border around one cell
00393    int hspace;                        // Value of HSPACE parameter
00394    int separation;                    // Space between columns
00395    int margin;                        // Space between left margin and 1st col
00396    int availWidth=0;                  // Part of lineWidth still available
00397    int maxTableWidth;                 // Amount of lineWidth available to table
00398    int fromAbove[HTML_MAX_COLUMNS+1]; // Cell above extends thru this row
00399    int min0span[HTML_MAX_COLUMNS+1];  // Min for colspan=0 cells
00400    int max0span[HTML_MAX_COLUMNS+1];  // Max for colspan=0 cells
00401    int reqW[HTML_MAX_COLUMNS+1];      // Requested width for each column
00402    int hasbg;
00403 
00404    // colMin[A][B] is the absolute minimum width of all columns between
00405    // A+1 and B+1.  colMin[B][A] is the requested width of columns between
00406    // A+1 and B+1.  This information is used to add in the constraints imposed
00407    // by <TD COLSPAN=N> markup where N>=2.
00408 
00409    int colMin[HTML_MAX_COLUMNS+1][HTML_MAX_COLUMNS+1];
00410 # define ColMin(A,B) colMin[(A)-1][(B)-1]
00411 # define ColReq(A,B) colMin[(B)-1][(A)-1]
00412 
00413    if (pStart == 0 || pStart->fType != Html_TABLE) return pStart;
00414 
00415    if (pStart->fBgImage) pStart->fHasbg = 1;
00416 
00417    TRACE_PUSH(HtmlTrace_Table1);
00418    TRACE(HtmlTrace_Table1, ("Starting TableDimensions... %s\n",
00419         pStart->MarkupArg("name", "")));
00420 
00421    pStart->fNCol = 0;
00422    pStart->fNRow = 0;
00423 
00424    z = pStart->MarkupArg("border", 0);
00425    if (z && *z == 0) z = "2";
00426 
00427    tbw = z ? atoi(z) : DFLT_BORDER;
00428    if (fTableBorderMin && tbw < fTableBorderMin) tbw = fTableBorderMin;
00429    pStart->fBorderWidth = tbw;
00430 
00431    cbw = (tbw > 0);
00432 
00433    z = pStart->MarkupArg("cellpadding", 0);
00434    cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
00435    cellSpacing = CellSpacing(pStart);
00436 
00437 #ifdef DEBUG
00438    // The HtmlTrace_Table4 flag causes tables to be draw with borders
00439    // of 2, cellPadding of 5 and cell spacing of 2.  This makes the
00440    // table clearly visible.  Useful for debugging. */
00441    if (HtmlTraceMask & HtmlTrace_Table4) {
00442       tbw = pStart->fBorderWidth = 2;
00443       cbw = 1;
00444       cellPadding = 5;
00445       cellSpacing = 2;
00446       pStart->fStyle.fBgcolor = COLOR_Background;
00447    }
00448 #endif
00449 
00450    separation = cellSpacing + 2 * (cellPadding + cbw);
00451    margin = tbw + cellSpacing + cbw + cellPadding;
00452 
00453    z = pStart->MarkupArg("hspace", 0);
00454    hspace = z ? atoi(z) : DFLT_HSPACE;
00455 
00456    // Figure out the maximum space available
00457    z = pStart->MarkupArg("width", 0);
00458    if (z) {
00459       int len = strlen(z);
00460       if (len > 0 && z[len-1] == '%') {
00461          maxTableWidth = (atoi(z) * lineWidth) / 100;
00462       } else {
00463          maxTableWidth = atoi(z);
00464       }
00465    } else {
00466       maxTableWidth = lineWidth;
00467    }
00468    maxTableWidth -= 2 * margin;
00469    SETMAX(maxTableWidth, 1);
00470 
00471    TRACE(HtmlTrace_Table1, ("lineWidth = %d, maxTableWidth = %d, margin = %d\n",
00472          lineWidth, maxTableWidth, margin));
00473 
00474    for (p = pStart->fPNext; p; p = fPNext) {
00475       if (p->fType == Html_EndTABLE) {
00476           ((TGHtmlRef *)p)->fPOther = pStart;
00477          pStart->fPEnd = p;
00478          break;
00479       }
00480 
00481       fPNext = p->fPNext;
00482 
00483       switch (p->fType) {
00484          case Html_EndTD:
00485          case Html_EndTH:
00486          case Html_EndTABLE:
00487             ((TGHtmlRef *)p)->fPOther = pStart;
00488             inCol = 0;
00489             break;
00490 
00491          case Html_EndTR:
00492             ((TGHtmlRef *)p)->fPOther = pStart;
00493             inRow = 0;
00494             break;
00495 
00496          case Html_TR:
00497             ((TGHtmlRef *)p)->fPOther = pStart;
00498             iRow++;
00499             pStart->fNRow++;
00500             iCol1 = 0;
00501             inRow = p;
00502             availWidth = maxTableWidth;
00503             break;
00504 
00505          case Html_CAPTION:
00506             while (p && p->fType != Html_EndTABLE
00507                    && p->fType != Html_EndCAPTION) p = p->fPNext;
00508             break;
00509 
00510          case Html_TD:
00511          case Html_TH: {
00512             TGHtmlCell *cell = (TGHtmlCell *) p;
00513             inCol = p;
00514             if (!inRow) {
00515                // If the <TR> markup is omitted, insert it.
00516                TGHtmlElement *pNew = new TGHtmlRef(Html_TR, 1, 0, 0);
00517                if (pNew == 0) break;
00518                //pNew->fType = Html_TR;
00519                pNew->fCount = 0;
00520                pNew->fStyle = p->fStyle;
00521                pNew->fFlags = p->fFlags;
00522                pNew->fPNext = p;
00523                p->fPPrev->fPNext = pNew;
00524                p->fPPrev = pNew;
00525                fPNext = pNew;
00526                break;
00527             }
00528             do {
00529                iCol1++;
00530             } while (iCol1 <= pStart->fNCol && fromAbove[iCol1] > iRow);
00531             cell->fPTable = pStart;
00532             cell->fPRow = inRow;
00533             colspan = cell->fColspan;
00534             if (colspan == 0) colspan = 1;
00535             if (iCol1 + colspan - 1 > pStart->fNCol) {
00536                int nCol = iCol1 + colspan - 1;
00537                if (nCol > HTML_MAX_COLUMNS) nCol = HTML_MAX_COLUMNS;
00538                for (i = pStart->fNCol + 1; i <= nCol; i++) {
00539                   fromAbove[i] = 0;
00540                   pStart->fMinW[i] = 0;
00541                   pStart->fMaxW[i] = 0;
00542                   min0span[i] = 0;
00543                   max0span[i] = 0;
00544                   reqW[i] = 0;
00545                   for (j = 1; j < i; j++) {
00546                      ColMin(j,i) = 0;
00547                      ColReq(j,i) = 0;
00548                   }
00549                }
00550                pStart->fNCol = nCol;
00551             }
00552             noWrap = (p->MarkupArg("nowrap", 0) != 0);
00553             hasbg = (pStart->fHasbg || ((TGHtmlRef *)cell->fPRow)->fBgImage ||
00554                      cell->fBgImage);
00555             fPNext = MinMax(p, &minW, &maxW, availWidth, hasbg);
00556             cell->fPEnd = fPNext;
00557             requestedW = 0;
00558             if ((z = p->MarkupArg("width", 0)) != 0) {
00559                for (i = 0; isdigit(z[i]) || z[i] == '.'; i++) {}
00560                if (strcmp(z, "*") == 0) {
00561                   requestedW = availWidth;
00562                } else if (z[i] == 0) {
00563                   requestedW = atoi(z);
00564                } else if (z[i] == '%') {
00565                   requestedW = (atoi(z) * maxTableWidth + 99) / 100;
00566                }
00567             }
00568 
00569             TRACE(HtmlTrace_Table1,
00570                   ("Row %d Column %d: min=%d max=%d req=%d stop at %s\n",
00571                   iRow, iCol1, minW, maxW, requestedW,
00572                   GetTokenName(((TGHtmlCell *)p)->fPEnd)));
00573 
00574             if (noWrap) {
00575                if ((z = p->MarkupArg("rowspan", 0)) == 0) { // Hack ???
00576                //minW = (requestedW > 0 ? requestedW : maxW);
00577                } else {
00578                   minW = maxW;
00579                }
00580             }
00581             if (iCol1 + cell->fColspan <= HTML_MAX_COLUMNS) {
00582                int min = 0;
00583                if (cell->fColspan == 0) {
00584                   SETMAX(min0span[iCol1], minW);
00585                   SETMAX(max0span[iCol1], maxW);
00586                   min = min0span[iCol1] + separation;
00587                } else if (colspan == 1) {
00588                   SETMAX(pStart->fMinW[iCol1], minW);
00589                   SETMAX(pStart->fMaxW[iCol1], maxW);
00590                   SETMAX(reqW[iCol1], requestedW);
00591                   min = pStart->fMinW[iCol1] + separation;
00592                } else {
00593                   int n2 = cell->fColspan;
00594                   int per = maxW / n2;
00595                   int ix;
00596                   SETMAX(ColMin(iCol1, iCol1+n2-1), minW);
00597                   SETMAX(ColReq(iCol1, iCol1+n2-1), requestedW);
00598                   min = minW + separation;
00599                   for (ix = iCol1; ix < iCol1 + n2; ix++) {
00600                      if (minW != maxW) {  //-- without this some tables are not displayed properly
00601                         SETMAX(pStart->fMaxW[ix], per);
00602                      }
00603                   }
00604                }
00605                availWidth -= min;
00606             }
00607             rowspan = cell->fRowspan;
00608             if (rowspan == 0) rowspan = LARGE_NUMBER;
00609             if (rowspan > 1) {
00610                for (i = iCol1; i < iCol1 + cell->fColspan && i < HTML_MAX_COLUMNS; i++) {
00611                   fromAbove[i] = iRow + rowspan;
00612                }
00613             }
00614             if (cell->fColspan > 1) {
00615                iCol1 += cell->fColspan - 1;
00616             } else if (cell->fColspan == 0) {
00617                iCol1 = HTML_MAX_COLUMNS + 1;
00618             }
00619             break;
00620          }
00621       }
00622    }
00623 
00624 #ifdef DEBUG
00625    if (HtmlTraceMask & HtmlTrace_Table6) {
00626       const char *zSpace = "";
00627       TRACE_INDENT;
00628       for (i = 1; i <= pStart->fNCol; i++) {
00629          printf("%s%d:%d..%d", zSpace, i, pStart->fMinW[i], pStart->fMaxW[i]);
00630          if (reqW[i] > 0) {
00631             printf("(w=%d)", reqW[i]);
00632          }
00633          zSpace = "  ";
00634       }
00635       printf("\n");
00636       for (i = 1; i < pStart->fNCol; i++) {
00637          for (j = i+1; j <= pStart->fNCol; j++) {
00638             if (ColMin(i, j) > 0) {
00639                TRACE_INDENT;
00640                printf("ColMin(%d,%d) = %d\n", i, j, ColMin(i, j));
00641             }
00642             if (ColReq(i, j) > 0) {
00643                TRACE_INDENT;
00644                printf("ColReq(%d,%d) = %d\n", i, j, ColReq(i, j));
00645             }
00646          }
00647       }
00648    }
00649 #endif
00650 
00651    // Compute the min and max width of each column
00652 
00653    for (i = 1; i <= pStart->fNCol; i++) {
00654       int sumMin, sumReq, sumMax;
00655 
00656       // Reduce the max[] field to N for columns that have "width=N"
00657       if (reqW[i] > 0) {
00658          pStart->fMaxW[i] = MAX(pStart->fMinW[i], reqW[i]);
00659       }
00660 
00661       // Expand the width of columns marked with "colspan=0".
00662 
00663       if (min0span[i] > 0 || max0span[i] > 0) {
00664          int n2 = pStart->fNCol - i + 1;
00665          minW = (min0span[i] + (n2 - 1) * (1 - separation)) / n2;
00666          maxW = (max0span[i] + (n2 - 1) * (1 - separation)) / n2;
00667          for (j = i; j <= pStart->fNCol; j++) {
00668             SETMAX(pStart->fMinW[j], minW);
00669             SETMAX(pStart->fMaxW[j], maxW);
00670          }
00671       }
00672 
00673       // Expand the minW[] of columns to accomodate "colspan=N" constraints.
00674       // The minW[] is expanded up to the maxW[] first.  Then all the maxW[]s
00675       // are expanded in proportion to their sizes.  The same thing occurs
00676       // for reqW[]s.
00677 
00678       sumReq = reqW[i];
00679       sumMin = pStart->fMinW[i];
00680       sumMax = pStart->fMaxW[i];
00681       for (j = i-1; j >= 1; j--) {
00682          int cmin, creq;
00683 
00684          sumMin += pStart->fMinW[j];
00685          sumMax += pStart->fMaxW[j];
00686          sumReq += reqW[i];
00687          cmin = ColMin(j, i);
00688 
00689          if (cmin > sumMin) {
00690             int k;
00691             double scale;
00692 
00693             int *tminW = pStart->fMinW;
00694             int *tmaxW = pStart->fMaxW;
00695             if (sumMin < sumMax) {
00696                scale = (double) (cmin - sumMin) / (double) (sumMax - sumMin);
00697                for (k = j; k <= i; k++) {
00698                   sumMin -= tminW[k];
00699                   tminW[k] = (int) ((tmaxW[k] - tminW[k]) * scale + tminW[k]);
00700                   sumMin += tminW[k];
00701                }
00702             } else if (sumMin > 0) {
00703                scale = (double) cmin / (double) sumMin;
00704                for (k = j; k <= i; k++) {
00705                   sumMin -= tminW[k];
00706                   tminW[k] = tmaxW[k] = (int) (tminW[k] * scale);
00707                   sumMin += tminW[k];
00708                }
00709             } else {
00710                int unit = cmin / (i - j + 1);
00711                for (k = j; k <= i; k++) {
00712                   tminW[k] = tmaxW[k] = unit;
00713                   sumMin += tminW[k];
00714                }
00715             }
00716          }
00717 
00718          creq = ColReq(j, i);
00719          if (creq > sumReq) {
00720             int k;
00721             double scale;
00722 
00723             int *tmaxW = pStart->fMaxW;
00724             if (sumReq < sumMax) {
00725                scale = (double) (creq - sumReq) / (double) (sumMax - sumReq);
00726                for (k = j; k <= i; k++) {
00727                   sumReq -= reqW[k];
00728                   reqW[k] = (int) ((tmaxW[k] - reqW[k]) * scale + reqW[k]);
00729                   sumReq += reqW[k];
00730                }
00731             } else if (sumReq > 0) {
00732                scale = (double) creq / (double) sumReq;
00733                for (k = j; k <= i; k++) {
00734                   sumReq -= reqW[k];
00735                   reqW[k] = (int) (reqW[k] * scale);
00736                   sumReq += reqW[k];
00737                }
00738             } else {
00739                int unit = creq / (i - j + 1);
00740                for (k = j; k <= i; k++) {
00741                   reqW[k] = unit;
00742                   sumReq += reqW[k];
00743                }
00744             }
00745          }
00746       }
00747    }
00748 
00749 #ifdef DEBUG
00750    if (HtmlTraceMask & HtmlTrace_Table6) {
00751       const char *zSpace = "";
00752       TRACE_INDENT;
00753       for (i = 1; i <= pStart->fNCol; i++) {
00754          printf("%s%d:%d..%d", zSpace, i, pStart->fMinW[i], pStart->fMaxW[i]);
00755          if (reqW[i] > 0) {
00756             printf("(w=%d)", reqW[i]);
00757          }
00758          zSpace = "  ";
00759       }
00760       printf("\n");
00761    }
00762 #endif
00763 
00764    // Compute the min and max width of the whole table
00765 
00766    n = pStart->fNCol;
00767    requestedW = tbw * 2 + (n + 1) * cellSpacing + n * 2 * (cellPadding + cbw);
00768    pStart->fMinW[0] = requestedW;
00769    pStart->fMaxW[0] = requestedW;
00770    for (i = 1; i <= pStart->fNCol; i++) {
00771       pStart->fMinW[0] += pStart->fMinW[i];
00772       pStart->fMaxW[0] += pStart->fMaxW[i];
00773       requestedW += MAX(reqW[i], pStart->fMinW[i]);
00774    }
00775 
00776    // Possibly widen or narrow the table to accomodate a "width=" attribute
00777    z = pStart->MarkupArg("width", 0);
00778    if (z) {
00779       int len = strlen(z);
00780       int totalWidth;
00781       if (len > 0 && z[len-1] == '%') {
00782          totalWidth = (atoi(z) * lineWidth) / 100;
00783       } else {
00784          totalWidth = atoi(z);
00785       }
00786       SETMAX(totalWidth, pStart->fMinW[0]);
00787 #if 1
00788       requestedW = totalWidth;
00789 #else
00790       SETMAX(requestedW, totalWidth); //-- makes it too narrow
00791 #endif
00792    }
00793    SETMAX(maxTableWidth, pStart->fMinW[0]);
00794    if (lineWidth && (requestedW > lineWidth)) {
00795 
00796       TRACE(HtmlTrace_Table5, ("RequestedW reduced to lineWidth: %d -> %d\n",
00797             requestedW, lineWidth));
00798 
00799       requestedW = lineWidth;
00800    }
00801    if (requestedW > pStart->fMinW[0]) {
00802       float scale;
00803       int *tminW = pStart->fMinW;
00804       int *tmaxW = pStart->fMaxW;
00805 
00806       TRACE(HtmlTrace_Table5,
00807             ("Expanding table minW from %d to %d.  (reqW=%d width=%s)\n",
00808              tminW[0], requestedW, requestedW, z));
00809 
00810       if (tmaxW[0] > tminW[0]) {
00811          scale = (double) (requestedW - tminW[0]) / (double) (tmaxW[0] - tminW[0]);
00812          for (i = 1; i <= pStart->fNCol; i++) {
00813             tminW[i] += (int) ((tmaxW[i] - tminW[i]) * scale);
00814             SETMAX(tmaxW[i], tminW[i]);
00815          }
00816       } else if (tminW[0] > 0) {
00817          scale = requestedW / (double) tminW[0];
00818          for (i = 1; i <= pStart->fNCol; i++) {
00819             tminW[i] = (int) (tminW[i] * scale);
00820             tmaxW[i] = (int) (tmaxW[i] * scale);
00821          }
00822       } else if (pStart->fNCol > 0) {
00823          int unit = (requestedW - margin) / pStart->fNCol - separation;
00824          if (unit < 0) unit = 0;
00825          for (i = 1; i <= pStart->fNCol; i++) {
00826             tminW[i] = tmaxW[i] = unit;
00827          }
00828       } else {
00829          tminW[0] = tmaxW[0] = requestedW;
00830       }
00831       pStart->fMinW[0] = requestedW;
00832       SETMAX(pStart->fMaxW[0], requestedW);
00833    }
00834 
00835 #ifdef DEBUG
00836    if (HtmlTraceMask & HtmlTrace_Table5) {
00837       TRACE_INDENT;
00838       printf("Start with %s and ", GetTokenName(pStart));
00839       printf("end with %s\n", GetTokenName(p));
00840       TRACE_INDENT;
00841       printf("nCol=%d minWidth=%d maxWidth=%d\n",
00842       pStart->fNCol, pStart->fMinW[0], pStart->fMaxW[0]);
00843       for (i = 1; i <= pStart->fNCol; i++) {
00844          TRACE_INDENT;
00845          printf("Column %d minWidth=%d maxWidth=%d\n",
00846                 i, pStart->fMinW[i], pStart->fMaxW[i]);
00847       }
00848    }
00849 #endif
00850 
00851    TRACE(HtmlTrace_Table1,
00852          ("Result of TableDimensions: min=%d max=%d nCol=%d\n",
00853           pStart->fMinW[0], pStart->fMaxW[0], pStart->fNCol));
00854    TRACE_POP(HtmlTrace_Table1);
00855 
00856    return p;
00857 }
00858 
00859 //______________________________________________________________________________
00860 TGHtmlElement *TGHtml::MinMax(TGHtmlElement *p, int *pMin, int *pMax,
00861                              int /*lineWidth*/, int hasbg)
00862 {
00863    // Given a list of elements, compute the minimum and maximum width needed
00864    // to render the list.  Stop the search at the first element seen that is
00865    // in the following set:
00866    //
00867    //       <tr>  <td>  <th>  </tr>  </td>  </th>  </table>
00868    //
00869    // Return a pointer to the element that stopped the search, or to NULL
00870    // if we ran out of data.
00871    //
00872    // Sometimes the value returned for both min and max will be larger than
00873    // the true minimum and maximum.  This is rare, and only occurs if the
00874    // element string contains figures with flow-around text.
00875    //
00876    //  p         - Start the search here
00877    //  pMin      - Return the minimum width here
00878    //  pMax      - Return the maximum width here
00879    //  lineWidth - Total width available
00880 
00881    int min = 0;             // Minimum width so far
00882    int max = 0;             // Maximum width so far
00883    int indent = 0;          // Amount of indentation (minimum)
00884    int obstacle = 0;        // Possible obstacles in the margin
00885    int x1 = 0;              // Length of current line assuming maximum length
00886    int x2 = 0;              // Length of current line assuming minimum length
00887    int x3 = 0;              // Like x1, but only within <PRE> tag
00888    int go = 1;              // Change to 0 to stop the loop
00889    int inpre = 0;           // Are we in <PRE>
00890    TGHtmlElement *fPNext;     // Next element in the list
00891    int wstyle = 0;          // Current style for nowrap
00892 
00893    if (p->MarkupArg("nowrap", 0) != 0) {
00894       wstyle |= STY_NoBreak;
00895    }
00896 
00897    for (p = p->fPNext; go && p; p = fPNext) {
00898       fPNext = p->fPNext;
00899       if (!inpre) x3 = 0;
00900       switch (p->fType) {
00901          case Html_PRE:
00902             inpre = 1;
00903             break;
00904 
00905          case Html_EndPRE:
00906             inpre = 0;
00907             break;
00908 
00909          case Html_Text: {
00910             TGHtmlTextElement *text = (TGHtmlTextElement *) p;
00911             x1 += text->fW;
00912             x2 += text->fW;
00913             SETMAX(max, x1);
00914             if (p->fStyle.fFlags & STY_Preformatted) {
00915                x3 += text->fW;
00916                SETMAX(min, x3);
00917             } else {
00918                SETMAX(min, x2);
00919             }
00920             break;
00921          }
00922 
00923          case Html_Space: {
00924             TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
00925             p->fStyle.fFlags |= wstyle;
00926             if (p->fStyle.fFlags & STY_Preformatted) {
00927                if (p->fFlags & HTML_NewLine) {
00928                   x1 = x2 = x3 = indent;
00929                } else {
00930                   x1 += space->fW * p->fCount;
00931                   x2 += space->fW * p->fCount;
00932                   x3 += space->fW * p->fCount;
00933                }
00934             } else if (p->fStyle.fFlags & STY_NoBreak) {
00935                if (x1 > indent) x1 += space->fW;
00936                if (x2 > indent) x2 += space->fW;
00937             } else {
00938                if (x1 > indent) x1 += space->fW;
00939                x2 = indent;
00940             }
00941             break;
00942          }
00943 
00944          case Html_IMG: {
00945             TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
00946             switch (image->fAlign) {
00947                case IMAGE_ALIGN_Left:
00948                case IMAGE_ALIGN_Right:
00949                   obstacle += image->fW;
00950                   x1 = obstacle + indent;
00951                   x2 = indent;
00952                   SETMAX(min, x2);
00953                   SETMAX(min, image->fW);
00954                   SETMAX(max, x1);
00955                   break;
00956 
00957                default:
00958                   x1 += image->fW;
00959                   x2 += image->fW;
00960                   if (p->fStyle.fFlags & STY_Preformatted) {
00961                      SETMAX(min, x1);
00962                      SETMAX(max, x1);
00963                   } else {
00964                      SETMAX(min, x2);
00965                      SETMAX(max, x1);
00966                   }
00967                   break;
00968             }
00969             break;
00970          }
00971 
00972          case Html_TABLE: {
00973             TGHtmlTable *table = (TGHtmlTable *) p;
00974             /* fPNext = TableDimensions(table, lineWidth - indent); */
00975             table->fHasbg = hasbg;
00976             fPNext = TableDimensions(table, 0);
00977             x1 = table->fMaxW[0] + indent + obstacle;
00978             x2 = table->fMinW[0] + indent;
00979             SETMAX(max, x1);
00980             SETMAX(min, x2);
00981             x1 = indent + obstacle;
00982             x2 = indent;
00983             if (fPNext && fPNext->fType == Html_EndTABLE) fPNext = fPNext->fPNext;
00984             break;
00985          }
00986 
00987          case Html_UL:
00988          case Html_OL:
00989             indent += HTML_INDENT;
00990             x1 = indent + obstacle;
00991             x2 = indent;
00992             break;
00993 
00994          case Html_EndUL:
00995          case Html_EndOL:
00996             indent -= HTML_INDENT;
00997             if (indent < 0) indent = 0;
00998             x1 = indent + obstacle;
00999             x2 = indent;
01000             break;
01001 
01002          case Html_BLOCKQUOTE:
01003             indent += 2 * HTML_INDENT;
01004             x1 = indent + obstacle;
01005             x2 = indent;
01006             break;
01007 
01008          case Html_EndBLOCKQUOTE:
01009             indent -= 2 * HTML_INDENT;
01010             if (indent < 0) indent = 0;
01011             x1 = indent + obstacle;
01012             x2 = indent;
01013             break;
01014 
01015          case Html_APPLET:
01016          case Html_INPUT:
01017          case Html_SELECT:
01018          case Html_EMBED:
01019          case Html_TEXTAREA: {
01020             TGHtmlInput *input = (TGHtmlInput *) p;
01021             x1 += input->fW + input->fPadLeft;
01022             if (p->fStyle.fFlags & STY_Preformatted) {
01023                x3 += input->fW + input->fPadLeft;
01024                SETMAX(min, x3);
01025                SETMAX(max, x1);
01026                x2 += input->fW + input->fPadLeft;
01027             } else {
01028                SETMAX(min, indent + input->fW);
01029                SETMAX(max, x1);
01030                x2 = indent;
01031             }
01032             break;
01033          }
01034 
01035          case Html_BR:
01036          case Html_P:
01037          case Html_EndP:
01038          case Html_DIV:
01039          case Html_EndDIV:
01040          case Html_H1:
01041          case Html_EndH1:
01042          case Html_H2:
01043          case Html_EndH2:
01044          case Html_H3:
01045          case Html_EndH3:
01046          case Html_H4:
01047          case Html_EndH4:
01048          case Html_H5:
01049          case Html_H6:
01050             x1 = indent + obstacle;
01051             x2 = indent;
01052             break;
01053 
01054          case Html_EndTD:
01055          case Html_EndTH:
01056          case Html_CAPTION:
01057          case Html_EndTABLE:
01058          case Html_TD:
01059          case Html_TR:
01060          case Html_TH:
01061          case Html_EndTR:
01062             go = 0;
01063             break;
01064 
01065          default:
01066             break;
01067       }
01068 
01069       if (!go) break;
01070    }
01071 
01072    *pMin = min;
01073    *pMax = max;
01074 
01075    return p;
01076 }
01077 
01078 
01079 // Vertical alignments:
01080 
01081 #define VAlign_Unknown    0
01082 #define VAlign_Top        1
01083 #define VAlign_Bottom     2
01084 #define VAlign_Center     3
01085 #define VAlign_Baseline   4
01086 
01087 
01088 //______________________________________________________________________________
01089 int TGHtmlMarkupElement::GetVerticalAlignment(int dflt)
01090 {
01091    // Return the vertical alignment specified by the given element.
01092 
01093    const char *z;
01094    int rc;
01095 
01096    z = MarkupArg("valign", 0);
01097    if (z == 0) {
01098       rc = dflt;
01099    } else if (strcasecmp(z, "top") == 0) {
01100       rc = VAlign_Top;
01101    } else if (strcasecmp(z, "bottom") == 0) {
01102       rc = VAlign_Bottom;
01103    } else if (strcasecmp(z, "center") == 0) {
01104       rc = VAlign_Center;
01105    } else if (strcasecmp(z, "baseline") == 0) {
01106       rc = VAlign_Baseline;
01107    } else{
01108       rc = dflt;
01109    }
01110 
01111    return rc;
01112 }
01113 
01114 //______________________________________________________________________________
01115 TGHtmlElement *TGHtmlLayoutContext::TableLayout(TGHtmlTable *pTable)
01116 {
01117    // Do all layout for a single table.  Return the </table> element or
01118    // NULL if the table is unterminated.
01119 
01120    TGHtmlElement *pEnd1;       // The </table> element
01121    TGHtmlElement *p;           // For looping thru elements of the table
01122    TGHtmlElement *fPNext;       // Next element in the loop
01123    TGHtmlElement *pCaption;    // Start of the caption text.  The <caption>
01124    TGHtmlElement *pEndCaption; // End of the caption.  The </caption>
01125    int width;               // Width of the table as drawn
01126    int cellSpacing;         // Value of cellspacing= parameter to <table>
01127    int cellPadding;         // Value of cellpadding= parameter to <table>
01128    int tbw;                 // Width of the 3D border around the whole table
01129    int cbw;                 // Width of the 3D border around a cell
01130    int pad;                 // cellPadding + borderwidth
01131    const char *z;           // A string
01132    int left_margin;         // The left edge of space available for drawing
01133    int lineWidth;           // Total horizontal space available for drawing
01134    int specWidth;           // Total horizontal drawing width per width= attr
01135    int separation;          // Distance between content of columns (or rows)
01136    int i;                   // Loop counter
01137    int n;                   // Number of columns
01138    int btm;                 // Bottom edge of previous row
01139    int iRow;                // Current row number
01140    int iCol;                // Current column number
01141    int colspan;             // Number of columns spanned by current cell
01142    int vspace;              // Value of the vspace= parameter to <table>
01143    int hspace;              // Value of the hspace= parameter to <table>
01144    int rowBottom;           // Bottom edge of content in the current row
01145    int defaultVAlign;       // Default vertical alignment for the current row
01146    const char *zAlign;      // Value of the ALIGN= attribute of the <TABLE>
01147 #define N (HTML_MAX_COLUMNS+1)
01148    int y[N];                // Top edge of each cell's content
01149    int x[N];                // Left edge of each cell's content
01150    int w[N];                // Width of each cell's content
01151    int ymax[N];             // Bottom edge of cell's content if valign=top
01152    TGHtmlElement *apElem[N]; // The <td> or <th> for each cell in a row
01153    int firstRow[N];         // First row on which a cell appears
01154    int lastRow[N];          // Row to which each cell span's
01155    int valign[N];           // Vertical alignment for each cell
01156    TGHtmlLayoutContext savedContext;  // Saved copy of the original pLC
01157    TGHtmlLayoutContext cellContext;   // Used to render a single cell
01158 #ifdef TABLE_TRIM_BLANK
01159    extern int HtmlLineWasBlank;
01160 #endif // TABLE_TRIM_BLANK
01161 
01162    if (pTable == 0 || pTable->fType != Html_TABLE) return pTable;
01163 
01164    TRACE_PUSH(HtmlTrace_Table2);
01165    TRACE(HtmlTrace_Table2, ("Starting TableLayout() at %s\n",
01166                             fHtml->GetTokenName(pTable)));
01167 
01168    // Figure how much horizontal space is available for rendering
01169    // this table.  Store the answer in lineWidth.  left_margin is
01170    // the left-most X coordinate of the table.  btm stores the top-most
01171    // Y coordinate.
01172 
01173    ComputeMargins(&left_margin, &btm, &lineWidth);
01174 
01175    TRACE(HtmlTrace_Table2, ("...btm=%d left=%d width=%d\n",
01176                            btm, left_margin, lineWidth));
01177 
01178    // figure out how much space the table wants for each column,
01179    // and in total..
01180    pEnd1 = fHtml->TableDimensions(pTable, lineWidth);
01181 
01182    // If we don't have enough horizontal space to accomodate the minimum table
01183    // width, then try to move down past some obstruction (such as an
01184    // <IMG ALIGN=LEFT>) to give us more room.
01185 
01186    if (lineWidth < pTable->fMinW[0]) {
01187       WidenLine(pTable->fMinW[0], &left_margin, &btm, &lineWidth);
01188 
01189       TRACE(HtmlTrace_Table2, ("Widen to btm=%d left=%d width=%d\n",
01190                              btm, left_margin, lineWidth));
01191    }
01192    savedContext = *this;
01193 
01194   // Figure out how wide to draw the table
01195    z = pTable->MarkupArg("width", 0);
01196    if (z) {
01197       int len = strlen(z);
01198       if (len > 0 && z[len-1] == '%') {
01199          specWidth = (atoi(z) * lineWidth) / 100;
01200       } else {
01201          specWidth = atoi(z);
01202       }
01203    } else {
01204       specWidth = lineWidth;
01205    }
01206    if (specWidth < pTable->fMinW[0]) {
01207       width = pTable->fMinW[0];
01208    } else if (specWidth <= pTable->fMaxW[0]) {
01209       width = specWidth;
01210    } else {
01211       width = pTable->fMaxW[0];
01212    }
01213 
01214    // Compute the width and left edge position of every column in
01215    // the table
01216 
01217    z = pTable->MarkupArg("cellpadding", 0);
01218    cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
01219    cellSpacing = fHtml->CellSpacing(pTable);
01220 
01221    z = pTable->MarkupArg("vspace", 0);
01222    vspace = z ? atoi(z) : DFLT_VSPACE;
01223 
01224    z = pTable->MarkupArg("hspace", 0);
01225    hspace = z ? atoi(z) : DFLT_HSPACE;
01226 
01227 #ifdef DEBUG
01228    if (HtmlTraceMask & HtmlTrace_Table4) {
01229       cellPadding = 5;
01230       cellSpacing = 2;
01231       if (vspace < 2) vspace = 2;
01232       if (hspace < 2) hspace = 2;
01233    }
01234 #endif
01235 
01236    tbw = pTable->fBorderWidth;
01237    cbw = (tbw > 0);
01238    pad = cellPadding + cbw;
01239    separation = cellSpacing + 2 * pad;
01240    x[1] = left_margin + tbw + cellSpacing + pad;
01241 
01242    n = pTable->fNCol;
01243    if (n <= 0 || pTable->fMaxW[0] <= 0) {
01244       // Abort if the table has no columns at all or if the total width
01245       // of the table is zero or less.
01246       return pEnd1;
01247    }
01248 
01249    zAlign = pTable->MarkupArg("align", "");
01250    if (width <= lineWidth) {
01251       int align = pTable->fStyle.fAlign;
01252       if (align == ALIGN_Right || strcasecmp(zAlign, "right") == 0) {
01253          x[1] += lineWidth - width;
01254       } else if (align == ALIGN_Center && strcasecmp(zAlign, "left") != 0) {
01255          x[1] += (lineWidth - width) / 2;
01256       }
01257    }
01258 
01259    if (width == pTable->fMaxW[0]) {
01260       w[1] = pTable->fMaxW[1];
01261       for (i = 2; i <= n; i++) {
01262          w[i] = pTable->fMaxW[i];
01263          x[i] = x[i-1] + w[i-1] + separation;
01264       }
01265    } else if (width > pTable->fMaxW[0]) {
01266       int *tmaxW = pTable->fMaxW;
01267       double scale = ((double) width) / (double) tmaxW[0];
01268       w[1] = (int) (tmaxW[1] * scale);
01269       for (i = 2; i <= n; i++) {
01270          w[i] = (int) (tmaxW[i] * scale);
01271          x[i] = x[i-1] + w[i-1] + separation;
01272       }
01273    } else if (width > pTable->fMinW[0]) {
01274       float scale;
01275       int *tminW = pTable->fMinW;
01276       int *tmaxW = pTable->fMaxW;
01277       scale = (double) (width - tminW[0]) / (double) (tmaxW[0] - tminW[0]);
01278       w[1] = (int) (tminW[1] + (tmaxW[1] - tminW[1]) * scale);
01279       for (i = 2; i <= n; i++) {
01280          w[i] = (int) (tminW[i] + (tmaxW[i] - tminW[i]) * scale);
01281          x[i] = x[i-1] + w[i-1] + separation;
01282       }
01283    } else {
01284       w[1] = pTable->fMinW[1];
01285       for (i = 2; i <= n; i++) {
01286          w[i] = pTable->fMinW[i];
01287          x[i] = x[i-1] + w[i-1] + separation;
01288       }
01289    }
01290    w[n] = width - ((x[n] - x[1]) + 2 * (tbw + pad + cellSpacing));
01291 
01292    // Add notation to the pTable structure so that we will know where
01293    // to draw the outer box around the outside of the table.
01294 
01295    btm += vspace;
01296    pTable->fY = btm;
01297    pTable->fX = x[1] - (tbw + cellSpacing + pad);
01298    pTable->fW = width;
01299    SETMAX(fMaxX, pTable->fX + pTable->fW);
01300    btm += tbw + cellSpacing;
01301 
01302    // Begin rendering rows of the table
01303    for (i = 1; i <= n; i++) {
01304       firstRow[i] = 0;
01305       lastRow[i] = 0;
01306       apElem[i] = 0;
01307    }
01308    p = pTable->fPNext;
01309    rowBottom = btm;
01310    for (iRow = 1; iRow <= pTable->fNRow; iRow++) {
01311 
01312       TRACE(HtmlTrace_Table2, ("Row %d: btm=%d\n",iRow,btm));
01313 
01314       // Find the start of the next row. Keep an eye out for the caption
01315       // while we search
01316       while (p && p->fType != Html_TR) {
01317          if (p->fType == Html_CAPTION) {
01318             pCaption = p;
01319             while (p && p != pEnd1 && p->fType != Html_EndCAPTION) p = p->fPNext;
01320             pEndCaption = p;
01321          }
01322 
01323          TRACE(HtmlTrace_Table3, ("Skipping token %s\n", fHtml->GetTokenName(p)));
01324 
01325          if (p) p = p->fPNext;
01326       }
01327       if (p == 0) break;
01328 
01329       // Record default vertical alignment flag for this row
01330       defaultVAlign = p->GetVerticalAlignment(VAlign_Center);
01331 
01332       // Find every new cell on this row
01333       for (iCol = 1; iCol <= pTable->fNCol && iCol <= HTML_MAX_COLUMNS; iCol++) {
01334          if (lastRow[iCol] < iRow) ymax[iCol] = 0;
01335       }
01336       iCol = 0;
01337       for (p = p->fPNext; p && p->fType != Html_TR && p != pEnd1; p = fPNext) {
01338          fPNext = p->fPNext;
01339 
01340          TRACE(HtmlTrace_Table3, ("Processing token %s\n", fHtml->GetTokenName(p)));
01341 
01342          switch (p->fType) {
01343             case Html_TD:
01344             case Html_TH:
01345                // Find the column number for this cell. Be careful to skip
01346                // columns which extend down to this row from prior rows
01347                do {
01348                   iCol++;
01349                } while (iCol <= HTML_MAX_COLUMNS && lastRow[iCol] >= iRow);
01350 
01351                TRACE(HtmlTrace_Table2,
01352                      ("Column %d: x=%d w=%d\n",iCol,x[iCol],w[iCol]));
01353 
01354                // Process the new cell. (Cells beyond the maximum number of
01355                // cells are simply ignored.)
01356                if (iCol <= HTML_MAX_COLUMNS) {
01357                   TGHtmlCell *cell = (TGHtmlCell *) p;
01358                   apElem[iCol] = p;
01359                   fPNext = cell->fPEnd;
01360                   if (cell->fRowspan == 0) {
01361                      lastRow[iCol] = pTable->fNRow;
01362                   } else {
01363                      lastRow[iCol] = iRow + cell->fRowspan - 1;
01364                   }
01365                   firstRow[iCol] = iRow;
01366 
01367                   // Set vertical alignment flag for this cell
01368                   valign[iCol] = p->GetVerticalAlignment(defaultVAlign);
01369 
01370                   // Render cell contents and record the height
01371                   y[iCol] = btm + pad;
01372                   cellContext.fHtml     = fHtml;
01373                   cellContext.fPStart   = p->fPNext;
01374                   cellContext.fPEnd     = fPNext;
01375                   cellContext.fHeadRoom = 0;
01376                   cellContext.fTop      = y[iCol];
01377                   cellContext.fBottom   = y[iCol];
01378                   cellContext.fLeft     = x[iCol];
01379                   cellContext.fRight    = 0;
01380                   cellContext.fPageWidth = x[iCol] + w[iCol];
01381                   colspan = cell->fColspan;
01382                   if (colspan == 0) {
01383                      for (i = iCol + 1;
01384                           i <= pTable->fNCol && i <= HTML_MAX_COLUMNS; i++) {
01385                         cellContext.fPageWidth += w[i] + separation;
01386                         lastRow[i] = lastRow[iCol];
01387                      }
01388                   } else if (colspan > 1) {
01389                      for (i = iCol + 1;
01390                           i < iCol + colspan && i <= HTML_MAX_COLUMNS; i++) {
01391                         cellContext.fPageWidth += w[i] + separation;
01392                         lastRow[i] = lastRow[iCol];
01393                      }
01394                   }
01395                   cellContext.fMaxX = 0;
01396                   cellContext.fMaxY = 0;
01397                   cellContext.fLeftMargin = 0;
01398                   cellContext.fRightMargin = 0;
01399                   cellContext.LayoutBlock();
01400 #ifdef TABLE_TRIM_BLANK
01401                   // Cancel any trailing vertical whitespace caused
01402                   // by break markup
01403                   if (HtmlLineWasBlank) {
01404                      cellContext.fMaxY -= cellContext.headRoom;
01405                   }
01406 #endif // TABLE_TRIM_BLANK
01407                   ymax[iCol] = cellContext.fMaxY;
01408                   SETMAX(ymax[iCol], y[iCol]);
01409                   cellContext.ClearMarginStack(&cellContext.fLeftMargin);
01410                   cellContext.ClearMarginStack(&cellContext.fRightMargin);
01411 
01412                   // Set coordinates of the cell border
01413                   cell->fX = x[iCol] - pad;
01414                   cell->fY = btm;
01415                   cell->fW = cellContext.fPageWidth + 2 * pad - x[iCol];
01416 
01417                   TRACE(HtmlTrace_Table2,
01418                         ("Column %d top=%d bottom=%d h=%d left=%d w=%d\n",
01419                         iCol, y[iCol], ymax[iCol], ymax[iCol]-y[iCol],
01420                         cell->fX, cell->fW));
01421 
01422                   // Advance the column counter for cells spaning multiple columns
01423                   if (colspan > 1) {
01424                      iCol += colspan - 1;
01425                   } else if (colspan == 0) {
01426                      iCol = HTML_MAX_COLUMNS + 1;
01427                   }
01428                }
01429                break;
01430 
01431          case Html_CAPTION:
01432             // Gotta remember where the caption is so we can render it
01433             // at the end
01434             pCaption = p;
01435             while (fPNext && fPNext != pEnd1 && fPNext->fType != Html_EndCAPTION) {
01436                fPNext = fPNext->fPNext;
01437             }
01438             pEndCaption = fPNext;
01439             break;
01440          }
01441       }
01442 
01443       // Figure out how high to make this row.
01444       for (iCol = 1; iCol <= pTable->fNCol; iCol++) {
01445          if (lastRow[iCol] == iRow || iRow == pTable->fNRow) {
01446             SETMAX(rowBottom, ymax[iCol]);
01447          }
01448       }
01449 
01450       TRACE(HtmlTrace_Table2, ("Total row height: %d..%d -> %d\n",
01451                              btm,rowBottom,rowBottom-btm));
01452 
01453       // Position every cell whose bottom edge ends on this row
01454       for (iCol = 1; iCol <= pTable->fNCol; iCol++) {
01455          int dy = 0;    // Extra space at top of cell used for vertical alignment
01456          TGHtmlCell *apCell = (TGHtmlCell *) apElem[iCol];
01457 
01458          // Skip any unused cells or cells that extend down thru
01459          // subsequent rows
01460          if (apElem[iCol] == 0 ||
01461              (iRow != pTable->fNRow && lastRow[iCol] > iRow)) continue;
01462 
01463             // Align the contents of the cell vertically.
01464             switch (valign[iCol]) {
01465                case VAlign_Unknown:
01466                case VAlign_Center:
01467                   dy = (rowBottom - ymax[iCol])/2;
01468                   break;
01469             case VAlign_Top:
01470             case VAlign_Baseline:
01471                   dy = 0;
01472                   break;
01473             case VAlign_Bottom:
01474                   dy = rowBottom - ymax[iCol];
01475                   break;
01476             }
01477             if (dy) {
01478                TGHtmlElement *pLast = apCell->fPEnd;
01479 
01480                TRACE(HtmlTrace_Table3, ("Delta column %d by %d\n",iCol,dy));
01481 
01482                fHtml->MoveVertically(apElem[iCol]->fPNext, pLast, dy);
01483             }
01484 
01485             // Record the height of the cell so that the border can be drawn
01486             apCell->fH = rowBottom + pad - apCell->fY;
01487             apElem[iCol] = 0;
01488          }
01489 
01490          // Update btm to the height of the row we just finished setting
01491          btm = rowBottom + pad + cellSpacing;
01492       }
01493 
01494       btm += tbw;
01495       pTable->fH = btm - pTable->fY;
01496       SETMAX(fMaxY, btm);
01497       fBottom = btm + vspace;
01498 
01499       // Render the caption, if there is one
01500       if (pCaption) {
01501       }
01502 
01503       // Whenever we do any table layout, we need to recompute all the
01504       // TGHtmlBlocks. The following statement forces this.
01505       fHtml->ResetBlocks(); // fHtml->firstBlock = fHtml->lastBlock = 0;
01506 
01507       // Adjust the context for text that wraps around the table, if
01508       // requested by an ALIGN=RIGHT or ALIGN=LEFT attribute.
01509 
01510       if (strcasecmp(zAlign, "left") == 0) {
01511          savedContext.fMaxX = fMaxX;
01512          savedContext.fMaxY = fMaxY;
01513          *this = savedContext;
01514          PushMargin(&fLeftMargin, pTable->fW + 2, pTable->fY + pTable->fH + 2, 0);
01515       } else if (strcasecmp(zAlign, "right") == 0) {
01516          savedContext.fMaxX = fMaxX;
01517          savedContext.fMaxY = fMaxY;
01518          *this = savedContext;
01519          PushMargin(&fRightMargin, pTable->fW + 2, pTable->fY + pTable->fH + 2, 0);
01520       }
01521 
01522       // All done
01523 
01524       TRACE(HtmlTrace_Table2, (
01525             "Done with TableLayout().  x=%d y=%d w=%d h=%d Return %s\n",
01526             pTable->fX, pTable->fY, pTable->fW, pTable->fH,
01527             fHtml->GetTokenName(pEnd1)));
01528       TRACE_POP(HtmlTrace_Table2);
01529 
01530    return pEnd1;
01531 }
01532 
01533 //______________________________________________________________________________
01534 void TGHtml::MoveVertically(TGHtmlElement *p, TGHtmlElement *pLast1, int dy)
01535 {
01536    // Move all elements in the given list vertically by the amount dy
01537    //
01538    // p     - First element to move
01539    // pLast1 - Last element.  Do move this one
01540    // dy    - Amount by which to move
01541 
01542    if (dy == 0) return;
01543 
01544    while (p && p != pLast1) {
01545       switch (p->fType) {
01546          case Html_A:
01547             ((TGHtmlAnchor *)p)->fY += dy;
01548             break;
01549 
01550          case Html_Text:
01551             ((TGHtmlTextElement *)p)->fY += dy;
01552             break;
01553 
01554          case Html_LI:
01555             ((TGHtmlLi *)p)->fY += dy;
01556             break;
01557 
01558          case Html_TD:
01559          case Html_TH:
01560             ((TGHtmlCell *)p)->fY += dy;
01561             break;
01562 
01563          case Html_TABLE:
01564             ((TGHtmlTable *)p)->fY += dy;
01565             break;
01566 
01567          case Html_IMG:
01568             ((TGHtmlImageMarkup *)p)->fY += dy;
01569             break;
01570 
01571          case Html_INPUT:
01572          case Html_SELECT:
01573          case Html_APPLET:
01574          case Html_EMBED:
01575          case Html_TEXTAREA:
01576             ((TGHtmlInput *)p)->fY += dy;
01577             break;
01578 
01579          default:
01580             break;
01581       }
01582       p = p->fPNext;
01583    }
01584 }

Generated on Tue Jul 5 14:22:19 2011 for ROOT_528-00b_version by  doxygen 1.5.1