Logo ROOT   6.12/07
Reference Guide
TGHtmlTable.cxx
Go to the documentation of this file.
1 // $Id: TGHtmlTable.cxx,v 1.1 2007/05/04 17:07:01 brun Exp $
2 // Author: Valeriy Onuchin 03/05/2007
3 
4 /**************************************************************************
5 
6  HTML widget for xclass. Based on tkhtml 1.28
7  Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
8  Copyright (C) 2002-2003 Hector Peraza.
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Library General Public
12  License as published by the Free Software Foundation; either
13  version 2 of the License, or (at your option) any later version.
14 
15  This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Library General Public License for more details.
19 
20  You should have received a copy of the GNU Library General Public
21  License along with this library; if not, write to the Free
22  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 
24 **************************************************************************/
25 
26 // Routines for doing layout of HTML tables
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <math.h>
32 
33 #include "TGHtml.h"
34 
35 
36 // Default values for various table style parameters
37 
38 #define DFLT_BORDER 0
39 #define DFLT_CELLSPACING_3D 5
40 #define DFLT_CELLSPACING_FLAT 0
41 #define DFLT_CELLPADDING 2
42 #define DFLT_HSPACE 0
43 #define DFLT_VSPACE 0
44 
45 // Set parameter A to the maximum of A and B.
46 #define SETMAX(A,B) if ((A) < (B)) { (A) = (B); }
47 #define MAX(A,B) ((A) < (B) ? (B) : (A))
48 
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Return the appropriate cell spacing for the given table.
52 
54 {
55  const char *z;
56  int relief;
57  int cellSpacing;
58 
59  z = pTable->MarkupArg("cellspacing", 0);
60  if (z == 0) {
61  relief = fTableRelief;
62  if (relief == HTML_RELIEF_RAISED || relief == HTML_RELIEF_SUNKEN) {
63  cellSpacing = DFLT_CELLSPACING_3D;
64  } else {
65  cellSpacing = DFLT_CELLSPACING_FLAT;
66  }
67  } else {
68  cellSpacing = atoi(z);
69  }
70 
71  return cellSpacing;
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Return the height and width of string.
76 
77 void TGHtml::StringHW(const char *str, int *h, int *w)
78 {
79  const char *cp = str;
80  int nw = 0, nh = 1, mw = 0;
81  *h = 0; *w =0;
82 
83  if (!cp) return;
84 
85  while (*cp) {
86  if (*cp != '\n') {
87  nw++;
88  } else {
89  if (nw > mw) mw = nw;
90  nw = 0;
91  nh++;
92  }
93  cp++;
94  }
95  if (nw > mw) mw = nw;
96  *w = mw;
97  *h = nh;
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Return text and images from a table as lists.
102 /// The first list is a list of rows (which is a list of cells).
103 /// An optional second list is a list of images: row col charoffset tokenid.
104 /// Note: weve added the option to store data/attrs in array var directly.
105 ///
106 /// flag - include images
107 
109 {
110  int j, h, w,
111  nest = 0,
112  // intext = 0,
113  rows = 0,
114  cols = 0,
115  numcols = 0,
116  maxh = 1;
117  int cspans = 0,
118  rspanstart = 0,
119  images = flag & 1,
120  attrs = flag & 2;
121  unsigned short maxw[HTML_MAX_COLUMNS];
122  short rspans[HTML_MAX_COLUMNS];
123  char buf[100];
124  const char *cp;
125  TGHtmlElement *p, *pEnd;
126  TGString istr(""); // Information string
127  TGString substr(""); // Temp to collect current cell string.
128  TGString imgstr(""); // Image information
129  TGString attrstr(""); // Attribue information
130 
131  TGString *str = new TGString(""); // The result
132 
133  if (pTable->fType != Html_TABLE) return str;
134  if (!(pEnd = pTable->fPEnd)) {
135  delete str;
136  return 0;
137  }
138 
139  str->Append("{ "); // start sublist
140  if (attrs) {
141  attrstr.Append("{ "); // start sublist
142  AppendArglist(&attrstr, pTable);
143  attrstr.Append("} "); // end sublist
144  }
145  for (j = 0; j < HTML_MAX_COLUMNS; j++) {
146  maxw[j] = 0;
147  rspans[j] = 0;
148  }
149  nest = 1;
150  istr.Append("{ ");
151  p = pTable;
152  while (p && (p = p->fPNext)) {
153  if (attrs) {
154  switch (p->fType) {
155  case Html_EndTR:
156  break;
157 
158  case Html_TR:
159  break;
160  }
161  }
162 
163  switch (p->fType) {
164  case Html_TABLE:
165  if (!(p = FindEndNest(p, Html_EndTABLE, 0))) {
166  delete str;
167  return 0;
168  }
169  break;
170 
171  case Html_EndTABLE:
172  p = 0;
173  break;
174 
175  case Html_TR:
176  if (cols > numcols) numcols = cols;
177  maxh = 1;
178  cols = 0;
179  rows++;
180  nest++;
181  str->Append("{ ");
182  if (attrs) {
183  attrstr.Append("{ { ");
184  AppendArglist(&attrstr, (TGHtmlMarkupElement *) p);
185  attrstr.Append("} ");
186  }
187  break;
188 
189  case Html_EndTR:
190  snprintf(buf, 100, "%d ", maxh);
191  istr.Append(buf);
192  if (attrs) {
193  attrstr.Append("} ");
194  }
195  while (nest > 1) {
196  nest--;
197  str->Append("} ");
198  }
199  break;
200 
201  case Html_TD:
202  case Html_TH:
203  if ((!(cp = p->MarkupArg("colspan", 0))) || (cspans = atoi(cp)) <= 0) {
204  cspans = 1;
205  }
206  if ((cp = p->MarkupArg("rowspan", 0)) && (j = atoi(cp)) > 0 &&
207  cols < HTML_MAX_COLUMNS) {
208  rspans[cols] = j;
209  rspanstart = 1;
210  } else {
211  rspanstart = 0;
212  }
213  if (attrs) {
214  j = 0;
215  while ((cspans - j) > 0) {
216  attrstr.Append("{ ");
217  if (!j) AppendArglist(&attrstr, (TGHtmlMarkupElement *) p);
218  attrstr.Append("} ");
219  j++;
220  }
221  }
222  cols++;
223  substr = "";
224  break;
225 
226  case Html_EndTD:
227  case Html_EndTH:
228  if (!rspanstart) {
229  while (cols <= HTML_MAX_COLUMNS && rspans[cols-1]-- > 1) {
230  str->Append(" "); // (""); ??
231  cols++;
232  }
233  }
234  cp = substr.GetString();
235 
236  j = 0;
237  while ((cspans - j) > 0) {
238  str->Append(cp);
239  str->Append(" ");
240  if (!j) {
241  StringHW(cp, &h, &w);
242  if (h > maxh) maxh = h;
243  if (cols > 0 && cols <= HTML_MAX_COLUMNS) {
244  if (w > maxw[cols-1]) {
245  maxw[cols-1] = w;
246  }
247  }
248  }
249  j++;
250  cp = "";
251  }
252  cspans = 0;
253  break;
254 
255  case Html_Text:
256  substr.Append(((TGHtmlTextElement *)p)->fZText);
257  break;
258 
259  case Html_Space:
260  for (j = 0; j < p->fCount; j++) {
261  substr.Append(" ");
262  }
263 // if ((p->flag & HTML_NewLine) != 0)
264 // substr.Append("\n");
265  break;
266 
267  case Html_BR:
268  substr.Append("\n"); // ("\\n"); ??
269  break;
270 
271  case Html_CAPTION: // Should do something with Caption?
272  if (!(pEnd = FindEndNest(p, Html_EndCAPTION, 0))) {
273  p = pEnd;
274  }
275  break;
276 
277  case Html_IMG: // Images return: row col charoffset tokenid
278  if (!images) break;
279  snprintf(buf, sizeof(buf), "%d %d %d %d ", rows-1, cols-1,
280  substr.GetLength(), p->fElId);
281  imgstr.Append(buf);
282  break;
283  }
284  }
285 
286  while (nest--) str->Append("} ");
287  istr.Append("} { ");
288  for (j = 0; j < numcols && j < HTML_MAX_COLUMNS; j++) {
289  snprintf(buf, sizeof(buf), "%d ", maxw[j]);
290  istr.Append(buf);
291  }
292  istr.Append("} ");
293 
294  str->Append(istr.Data());
295  str->Append(" ");
296  if (attrs) {
297  str->Append("{ ");
298  str->Append(attrstr.Data());
299  str->Append("} ");
300  }
301  if (images) {
302  str->Append(imgstr.Data());
303  }
304 
305  return str;
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Find End tag en, but ignore intervening begin/end tag pairs.
310 ///
311 /// sp -- Pointer to start from
312 /// en -- End tag to search for
313 /// lp -- Last pointer to try
314 
316  TGHtmlElement *lp)
317 {
318  TGHtmlElement *p;
319  int lvl, n;
320 
321  p = sp->fPNext;
322  lvl = 0;
323  n = sp->fType;
324 
325  while (p) {
326  if (p == lp) return 0;
327  if (n == Html_LI) {
328  if (p->fType == Html_LI || p->fType == Html_EndUL ||
329  p->fType == Html_EndOL) {
330  if (p->fPPrev) return p->fPPrev;
331  return p;
332  }
333  } else if (p->fType == n) {
334  if (n == Html_OPTION) {
335  if (p->fPPrev) return p->fPPrev;
336  return p;
337  }
338  lvl++;
339  } else if (p->fType == en) {
340  if (!lvl--) return p;
341  }
342  switch (p->fType) {
343  case Html_TABLE: p = ((TGHtmlTable *)p)->fPEnd; break; // optimization
344  case Html_FORM: p = ((TGHtmlForm *)p)->fPEnd; break;
345  default: p = p->fPNext;
346  }
347  }
348 
349  return 0;
350 }
351 
352 ////////////////////////////////////////////////////////////////////////////////
353 /// pStart points to a <table>. Compute the number of columns, the
354 /// minimum and maximum size for each column and the overall minimum
355 /// and maximum size for this table and store these value in the
356 /// pStart structure. Return a pointer to the </table> element,
357 /// or to NULL if there is no </table>.
358 ///
359 /// The min and max size for column N (where the leftmost column has
360 /// N==1) is pStart->fMinW[1] and pStart->fMaxW[1]. The pStart->fMinW[0]
361 /// and pStart->fMaxW[0] entries contain the minimum and maximum widths
362 /// of the whole table, including any cell padding, cell spacing,
363 /// border width and "hspace". The values of pStart->fMinW[I] for I>=1
364 /// do not contain any cell padding, cell spacing or border width.
365 /// Only pStart->fMinW[0] contains these extra spaces.
366 ///
367 /// The back references from </table>, </tr>, </td> and </th> back to
368 /// the <table> markup are also filled in. And for each <td> and <th>
369 /// markup, the pTable and pEnd fields are set to their proper values.
370 ///
371 /// pStart - The <table> markup
372 /// lineWidth - Total width available to the table
373 
375 {
376  TGHtmlElement *p; // Element being processed
377  TGHtmlElement *fPNext; // Next element to process
378  int iCol1 = 0; // Current column number. 1..N
379  int iRow = 0; // Current row number
380  TGHtmlElement *inRow = 0; // Pointer to <TR>
381  int i, j; // Loop counters
382  int n; // Number of columns
383  int minW, maxW, requestedW; // min, max, requested width for a cell
384  int noWrap; // true for NOWRAP cells
385  int colspan; // Column span for the current cell
386  int rowspan; // Row span for the current cell
387  const char *z; // Value of a <table> parameter
388  int cellSpacing; // Value of CELLSPACING parameter
389  int cellPadding; // Value of CELLPADDING parameter
390  int tbw; // Width of border around whole table
391  int cbw; // Width of border around one cell
392  // int hspace; // Value of HSPACE parameter
393  int separation; // Space between columns
394  int margin; // Space between left margin and 1st col
395  int availWidth=0; // Part of lineWidth still available
396  int maxTableWidth; // Amount of lineWidth available to table
397  int fromAbove[HTML_MAX_COLUMNS+1]={0}; // Cell above extends thru this row
398  int min0span[HTML_MAX_COLUMNS+1]={0}; // Min for colspan=0 cells
399  int max0span[HTML_MAX_COLUMNS+1]={0}; // Max for colspan=0 cells
400  int reqW[HTML_MAX_COLUMNS+1]={0}; // Requested width for each column
401  int hasbg;
402 
403  // colMin[A][B] is the absolute minimum width of all columns between
404  // A+1 and B+1. colMin[B][A] is the requested width of columns between
405  // A+1 and B+1. This information is used to add in the constraints imposed
406  // by <TD COLSPAN=N> markup where N>=2.
407 
408  int colMin[HTML_MAX_COLUMNS+1][HTML_MAX_COLUMNS+1];
409 # define ColMin(A,B) colMin[(A)-1][(B)-1]
410 # define ColReq(A,B) colMin[(B)-1][(A)-1]
411 
412  if (pStart == 0 || pStart->fType != Html_TABLE) return pStart;
413 
414  if (pStart->fBgImage) pStart->fHasbg = 1;
415 
417  TRACE(HtmlTrace_Table1, ("Starting TableDimensions... %s\n",
418  pStart->MarkupArg("name", "")));
419 
420  pStart->fNCol = 0;
421  pStart->fNRow = 0;
422 
423  z = pStart->MarkupArg("border", 0);
424  if (z && *z == 0) z = "2";
425 
426  tbw = z ? atoi(z) : DFLT_BORDER;
427  if (fTableBorderMin && tbw < fTableBorderMin) tbw = fTableBorderMin;
428  pStart->fBorderWidth = tbw;
429 
430  cbw = (tbw > 0);
431 
432  z = pStart->MarkupArg("cellpadding", 0);
433  cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
434  cellSpacing = CellSpacing(pStart);
435 
436 #ifdef DEBUG
437  // The HtmlTrace_Table4 flag causes tables to be draw with borders
438  // of 2, cellPadding of 5 and cell spacing of 2. This makes the
439  // table clearly visible. Useful for debugging. */
441  tbw = pStart->fBorderWidth = 2;
442  cbw = 1;
443  cellPadding = 5;
444  cellSpacing = 2;
445  pStart->fStyle.fBgcolor = COLOR_Background;
446  }
447 #endif
448 
449  separation = cellSpacing + 2 * (cellPadding + cbw);
450  margin = tbw + cellSpacing + cbw + cellPadding;
451 
452  z = pStart->MarkupArg("hspace", 0);
453  // hspace = z ? atoi(z) : DFLT_HSPACE;
454 
455  // Figure out the maximum space available
456  z = pStart->MarkupArg("width", 0);
457  if (z) {
458  int len = strlen(z);
459  if (len > 0 && z[len-1] == '%') {
460  maxTableWidth = (atoi(z) * lineWidth) / 100;
461  } else {
462  maxTableWidth = atoi(z);
463  }
464  } else {
465  maxTableWidth = lineWidth;
466  }
467  maxTableWidth -= 2 * margin;
468  SETMAX(maxTableWidth, 1);
469 
470  TRACE(HtmlTrace_Table1, ("lineWidth = %d, maxTableWidth = %d, margin = %d\n",
471  lineWidth, maxTableWidth, margin));
472 
473  for (p = pStart->fPNext; p; p = fPNext) {
474  if (p->fType == Html_EndTABLE) {
475  ((TGHtmlRef *)p)->fPOther = pStart;
476  pStart->fPEnd = p;
477  break;
478  }
479 
480  fPNext = p->fPNext;
481 
482  switch (p->fType) {
483  case Html_EndTD:
484  case Html_EndTH:
485  case Html_EndTABLE:
486  ((TGHtmlRef *)p)->fPOther = pStart;
487  // inCol = 0;
488  break;
489 
490  case Html_EndTR:
491  ((TGHtmlRef *)p)->fPOther = pStart;
492  inRow = 0;
493  break;
494 
495  case Html_TR:
496  ((TGHtmlRef *)p)->fPOther = pStart;
497  iRow++;
498  pStart->fNRow++;
499  iCol1 = 0;
500  inRow = p;
501  availWidth = maxTableWidth;
502  break;
503 
504  case Html_CAPTION:
505  while (p && p->fType != Html_EndTABLE
506  && p->fType != Html_EndCAPTION) p = p->fPNext;
507  break;
508 
509  case Html_TD:
510  case Html_TH: {
511  TGHtmlCell *cell = (TGHtmlCell *) p;
512  // inCol = p;
513  if (!inRow) {
514  // If the <TR> markup is omitted, insert it.
515  TGHtmlElement *pNew = new TGHtmlRef(Html_TR, 1, 0, 0);
516  if (pNew == 0) break;
517  //pNew->fType = Html_TR;
518  pNew->fCount = 0;
519  pNew->fStyle = p->fStyle;
520  pNew->fFlags = p->fFlags;
521  pNew->fPNext = p;
522  p->fPPrev->fPNext = pNew;
523  p->fPPrev = pNew;
524  fPNext = pNew;
525  break;
526  }
527  do {
528  iCol1++;
529  } while (iCol1 <= pStart->fNCol && fromAbove[iCol1] > iRow);
530  cell->fPTable = pStart;
531  cell->fPRow = inRow;
532  colspan = cell->fColspan;
533  if (colspan == 0) colspan = 1;
534  if (iCol1 + colspan - 1 > pStart->fNCol) {
535  int nCol = iCol1 + colspan - 1;
536  if (nCol > HTML_MAX_COLUMNS) nCol = HTML_MAX_COLUMNS;
537  for (i = pStart->fNCol + 1; i <= nCol; i++) {
538  fromAbove[i] = 0;
539  pStart->fMinW[i] = 0;
540  pStart->fMaxW[i] = 0;
541  min0span[i] = 0;
542  max0span[i] = 0;
543  reqW[i] = 0;
544  for (j = 1; j < i; j++) {
545  ColMin(j,i) = 0;
546  ColReq(j,i) = 0;
547  }
548  }
549  pStart->fNCol = nCol;
550  }
551  noWrap = (p->MarkupArg("nowrap", 0) != 0);
552  hasbg = (pStart->fHasbg || ((TGHtmlRef *)cell->fPRow)->fBgImage ||
553  cell->fBgImage);
554  fPNext = MinMax(p, &minW, &maxW, availWidth, hasbg);
555  cell->fPEnd = fPNext;
556  requestedW = 0;
557  if ((z = p->MarkupArg("width", 0)) != 0) {
558  for (i = 0; isdigit(z[i]) || z[i] == '.'; i++) {}
559  if (strcmp(z, "*") == 0) {
560  requestedW = availWidth;
561  } else if (z[i] == 0) {
562  requestedW = atoi(z);
563  } else if (z[i] == '%') {
564  requestedW = (atoi(z) * maxTableWidth + 99) / 100;
565  }
566  }
567 
569  ("Row %d Column %d: min=%d max=%d req=%d stop at %s\n",
570  iRow, iCol1, minW, maxW, requestedW,
571  GetTokenName(((TGHtmlCell *)p)->fPEnd)));
572 
573  if (noWrap) {
574  // coverity[returned_pointer]
575  if ((z = p->MarkupArg("rowspan", 0)) == 0) { // Hack ???
576  //minW = (requestedW > 0 ? requestedW : maxW);
577  } else {
578  minW = maxW;
579  }
580  }
581  if (iCol1 + cell->fColspan <= HTML_MAX_COLUMNS) {
582  int min = 0;
583  if (cell->fColspan == 0) {
584  SETMAX(min0span[iCol1], minW);
585  SETMAX(max0span[iCol1], maxW);
586  min = min0span[iCol1] + separation;
587  } else if (colspan == 1) {
588  SETMAX(pStart->fMinW[iCol1], minW);
589  SETMAX(pStart->fMaxW[iCol1], maxW);
590  SETMAX(reqW[iCol1], requestedW);
591  min = pStart->fMinW[iCol1] + separation;
592  } else {
593  int n2 = cell->fColspan;
594  int per = maxW / n2;
595  int ix;
596  SETMAX(ColMin(iCol1, iCol1+n2-1), minW);
597  SETMAX(ColReq(iCol1, iCol1+n2-1), requestedW);
598  min = minW + separation;
599  for (ix = iCol1; ix < iCol1 + n2; ix++) {
600  if (minW != maxW) { //-- without this some tables are not displayed properly
601  SETMAX(pStart->fMaxW[ix], per);
602  }
603  }
604  }
605  availWidth -= min;
606  }
607  rowspan = cell->fRowspan;
608  if (rowspan == 0) rowspan = LARGE_NUMBER;
609  if (rowspan > 1) {
610  for (i = iCol1; i < iCol1 + cell->fColspan && i < HTML_MAX_COLUMNS; i++) {
611  fromAbove[i] = iRow + rowspan;
612  }
613  }
614  if (cell->fColspan > 1) {
615  iCol1 += cell->fColspan - 1;
616  } else if (cell->fColspan == 0) {
617  iCol1 = HTML_MAX_COLUMNS + 1;
618  }
619  break;
620  }
621  }
622  }
623 
624 #ifdef DEBUG
626  const char *zSpace = "";
627  TRACE_INDENT;
628  for (i = 1; i <= pStart->fNCol; i++) {
629  printf("%s%d:%d..%d", zSpace, i, pStart->fMinW[i], pStart->fMaxW[i]);
630  if (reqW[i] > 0) {
631  printf("(w=%d)", reqW[i]);
632  }
633  zSpace = " ";
634  }
635  printf("\n");
636  for (i = 1; i < pStart->fNCol; i++) {
637  for (j = i+1; j <= pStart->fNCol; j++) {
638  if (ColMin(i, j) > 0) {
639  TRACE_INDENT;
640  printf("ColMin(%d,%d) = %d\n", i, j, ColMin(i, j));
641  }
642  if (ColReq(i, j) > 0) {
643  TRACE_INDENT;
644  printf("ColReq(%d,%d) = %d\n", i, j, ColReq(i, j));
645  }
646  }
647  }
648  }
649 #endif
650 
651  // Compute the min and max width of each column
652 
653  for (i = 1; i <= pStart->fNCol; i++) {
654  int sumMin, sumReq, sumMax;
655 
656  // Reduce the max[] field to N for columns that have "width=N"
657  if (reqW[i] > 0) {
658  pStart->fMaxW[i] = MAX(pStart->fMinW[i], reqW[i]);
659  }
660 
661  // Expand the width of columns marked with "colspan=0".
662 
663  if (min0span[i] > 0 || max0span[i] > 0) {
664  int n2 = pStart->fNCol - i + 1;
665  minW = (min0span[i] + (n2 - 1) * (1 - separation)) / n2;
666  maxW = (max0span[i] + (n2 - 1) * (1 - separation)) / n2;
667  for (j = i; j <= pStart->fNCol; j++) {
668  SETMAX(pStart->fMinW[j], minW);
669  SETMAX(pStart->fMaxW[j], maxW);
670  }
671  }
672 
673  // Expand the minW[] of columns to accomodate "colspan=N" constraints.
674  // The minW[] is expanded up to the maxW[] first. Then all the maxW[]s
675  // are expanded in proportion to their sizes. The same thing occurs
676  // for reqW[]s.
677 
678  sumReq = reqW[i];
679  sumMin = pStart->fMinW[i];
680  sumMax = pStart->fMaxW[i];
681  for (j = i-1; j >= 1; j--) {
682  int cmin, creq;
683 
684  sumMin += pStart->fMinW[j];
685  sumMax += pStart->fMaxW[j];
686  sumReq += reqW[i];
687  cmin = ColMin(j, i);
688 
689  if (cmin > sumMin) {
690  int k;
691  double scale;
692 
693  int *tminW = pStart->fMinW;
694  int *tmaxW = pStart->fMaxW;
695  if (sumMin < sumMax) {
696  scale = (double) (cmin - sumMin) / (double) (sumMax - sumMin);
697  for (k = j; k <= i; k++) {
698  sumMin -= tminW[k];
699  tminW[k] = (int) ((tmaxW[k] - tminW[k]) * scale + tminW[k]);
700  sumMin += tminW[k];
701  }
702  } else if (sumMin > 0) {
703  scale = (double) cmin / (double) sumMin;
704  for (k = j; k <= i; k++) {
705  sumMin -= tminW[k];
706  tminW[k] = tmaxW[k] = (int) (tminW[k] * scale);
707  sumMin += tminW[k];
708  }
709  } else {
710  int unit = cmin / (i - j + 1);
711  for (k = j; k <= i; k++) {
712  tminW[k] = tmaxW[k] = unit;
713  sumMin += tminW[k];
714  }
715  }
716  }
717 
718  creq = ColReq(j, i);
719  if (creq > sumReq) {
720  int k;
721  double scale;
722 
723  int *tmaxW = pStart->fMaxW;
724  if (sumReq < sumMax) {
725  scale = (double) (creq - sumReq) / (double) (sumMax - sumReq);
726  for (k = j; k <= i; k++) {
727  sumReq -= reqW[k];
728  reqW[k] = (int) ((tmaxW[k] - reqW[k]) * scale + reqW[k]);
729  sumReq += reqW[k];
730  }
731  } else if (sumReq > 0) {
732  scale = (double) creq / (double) sumReq;
733  for (k = j; k <= i; k++) {
734  sumReq -= reqW[k];
735  reqW[k] = (int) (reqW[k] * scale);
736  sumReq += reqW[k];
737  }
738  } else {
739  int unit = creq / (i - j + 1);
740  for (k = j; k <= i; k++) {
741  reqW[k] = unit;
742  sumReq += reqW[k];
743  }
744  }
745  }
746  }
747  }
748 
749 #ifdef DEBUG
750  if (HtmlTraceMask & HtmlTrace_Table6) {
751  const char *zSpace = "";
752  TRACE_INDENT;
753  for (i = 1; i <= pStart->fNCol; i++) {
754  printf("%s%d:%d..%d", zSpace, i, pStart->fMinW[i], pStart->fMaxW[i]);
755  if (reqW[i] > 0) {
756  printf("(w=%d)", reqW[i]);
757  }
758  zSpace = " ";
759  }
760  printf("\n");
761  }
762 #endif
763 
764  // Compute the min and max width of the whole table
765 
766  n = pStart->fNCol;
767  requestedW = tbw * 2 + (n + 1) * cellSpacing + n * 2 * (cellPadding + cbw);
768  pStart->fMinW[0] = requestedW;
769  pStart->fMaxW[0] = requestedW;
770  for (i = 1; i <= pStart->fNCol; i++) {
771  pStart->fMinW[0] += pStart->fMinW[i];
772  pStart->fMaxW[0] += pStart->fMaxW[i];
773  requestedW += MAX(reqW[i], pStart->fMinW[i]);
774  }
775 
776  // Possibly widen or narrow the table to accomodate a "width=" attribute
777  z = pStart->MarkupArg("width", 0);
778  if (z) {
779  int len = strlen(z);
780  int totalWidth;
781  if (len > 0 && z[len-1] == '%') {
782  totalWidth = (atoi(z) * lineWidth) / 100;
783  } else {
784  totalWidth = atoi(z);
785  }
786  SETMAX(totalWidth, pStart->fMinW[0]);
787 #if 1
788  requestedW = totalWidth;
789 #else
790  SETMAX(requestedW, totalWidth); //-- makes it too narrow
791 #endif
792  }
793  SETMAX(maxTableWidth, pStart->fMinW[0]);
794  if (lineWidth && (requestedW > lineWidth)) {
795 
796  TRACE(HtmlTrace_Table5, ("RequestedW reduced to lineWidth: %d -> %d\n",
797  requestedW, lineWidth));
798 
799  requestedW = lineWidth;
800  }
801  if (requestedW > pStart->fMinW[0]) {
802  float scale;
803  int *tminW = pStart->fMinW;
804  int *tmaxW = pStart->fMaxW;
805 
807  ("Expanding table minW from %d to %d. (reqW=%d width=%s)\n",
808  tminW[0], requestedW, requestedW, z));
809 
810  if (tmaxW[0] > tminW[0]) {
811  scale = (double) (requestedW - tminW[0]) / (double) (tmaxW[0] - tminW[0]);
812  for (i = 1; i <= pStart->fNCol; i++) {
813  tminW[i] += (int) ((tmaxW[i] - tminW[i]) * scale);
814  SETMAX(tmaxW[i], tminW[i]);
815  }
816  } else if (tminW[0] > 0) {
817  scale = requestedW / (double) tminW[0];
818  for (i = 1; i <= pStart->fNCol; i++) {
819  tminW[i] = (int) (tminW[i] * scale);
820  tmaxW[i] = (int) (tmaxW[i] * scale);
821  }
822  } else if (pStart->fNCol > 0) {
823  int unit = (requestedW - margin) / pStart->fNCol - separation;
824  if (unit < 0) unit = 0;
825  for (i = 1; i <= pStart->fNCol; i++) {
826  tminW[i] = tmaxW[i] = unit;
827  }
828  } else {
829  tminW[0] = tmaxW[0] = requestedW;
830  }
831  pStart->fMinW[0] = requestedW;
832  SETMAX(pStart->fMaxW[0], requestedW);
833  }
834 
835 #ifdef DEBUG
837  TRACE_INDENT;
838  printf("Start with %s and ", GetTokenName(pStart));
839  printf("end with %s\n", GetTokenName(p));
840  TRACE_INDENT;
841  printf("nCol=%d minWidth=%d maxWidth=%d\n",
842  pStart->fNCol, pStart->fMinW[0], pStart->fMaxW[0]);
843  for (i = 1; i <= pStart->fNCol; i++) {
844  TRACE_INDENT;
845  printf("Column %d minWidth=%d maxWidth=%d\n",
846  i, pStart->fMinW[i], pStart->fMaxW[i]);
847  }
848  }
849 #endif
850 
852  ("Result of TableDimensions: min=%d max=%d nCol=%d\n",
853  pStart->fMinW[0], pStart->fMaxW[0], pStart->fNCol));
855 
856  return p;
857 }
858 
859 ////////////////////////////////////////////////////////////////////////////////
860 /// Given a list of elements, compute the minimum and maximum width needed
861 /// to render the list. Stop the search at the first element seen that is
862 /// in the following set:
863 ///
864 /// <tr> <td> <th> </tr> </td> </th> </table>
865 ///
866 /// Return a pointer to the element that stopped the search, or to NULL
867 /// if we ran out of data.
868 ///
869 /// Sometimes the value returned for both min and max will be larger than
870 /// the true minimum and maximum. This is rare, and only occurs if the
871 /// element string contains figures with flow-around text.
872 ///
873 /// p - Start the search here
874 /// pMin - Return the minimum width here
875 /// pMax - Return the maximum width here
876 /// lineWidth - Total width available
877 
878 TGHtmlElement *TGHtml::MinMax(TGHtmlElement *p, int *pMin, int *pMax,
879  int /*lineWidth*/, int hasbg)
880 {
881  int min = 0; // Minimum width so far
882  int max = 0; // Maximum width so far
883  int indent = 0; // Amount of indentation (minimum)
884  int obstacle = 0; // Possible obstacles in the margin
885  int x1 = 0; // Length of current line assuming maximum length
886  int x2 = 0; // Length of current line assuming minimum length
887  int x3 = 0; // Like x1, but only within <PRE> tag
888  int go = 1; // Change to 0 to stop the loop
889  int inpre = 0; // Are we in <PRE>
890  TGHtmlElement *fPNext; // Next element in the list
891  int wstyle = 0; // Current style for nowrap
892 
893  if (p->MarkupArg("nowrap", 0) != 0) {
894  wstyle |= STY_NoBreak;
895  }
896 
897  for (p = p->fPNext; go && p; p = fPNext) {
898  fPNext = p->fPNext;
899  if (!inpre) x3 = 0;
900  switch (p->fType) {
901  case Html_PRE:
902  inpre = 1;
903  break;
904 
905  case Html_EndPRE:
906  inpre = 0;
907  break;
908 
909  case Html_Text: {
911  x1 += text->fW;
912  x2 += text->fW;
913  SETMAX(max, x1);
914  if (p->fStyle.fFlags & STY_Preformatted) {
915  x3 += text->fW;
916  SETMAX(min, x3);
917  } else {
918  SETMAX(min, x2);
919  }
920  break;
921  }
922 
923  case Html_Space: {
924  TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
925  p->fStyle.fFlags |= wstyle;
926  if (p->fStyle.fFlags & STY_Preformatted) {
927  if (p->fFlags & HTML_NewLine) {
928  x1 = x2 = x3 = indent;
929  } else {
930  x1 += space->fW * p->fCount;
931  x2 += space->fW * p->fCount;
932  x3 += space->fW * p->fCount;
933  }
934  } else if (p->fStyle.fFlags & STY_NoBreak) {
935  if (x1 > indent) x1 += space->fW;
936  if (x2 > indent) x2 += space->fW;
937  } else {
938  if (x1 > indent) x1 += space->fW;
939  x2 = indent;
940  }
941  break;
942  }
943 
944  case Html_IMG: {
945  TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
946  switch (image->fAlign) {
947  case IMAGE_ALIGN_Left:
948  case IMAGE_ALIGN_Right:
949  obstacle += image->fW;
950  x1 = obstacle + indent;
951  x2 = indent;
952  SETMAX(min, x2);
953  SETMAX(min, image->fW);
954  SETMAX(max, x1);
955  break;
956 
957  default:
958  x1 += image->fW;
959  x2 += image->fW;
960  if (p->fStyle.fFlags & STY_Preformatted) {
961  SETMAX(min, x1);
962  SETMAX(max, x1);
963  } else {
964  SETMAX(min, x2);
965  SETMAX(max, x1);
966  }
967  break;
968  }
969  break;
970  }
971 
972  case Html_TABLE: {
973  TGHtmlTable *table = (TGHtmlTable *) p;
974  /* fPNext = TableDimensions(table, lineWidth - indent); */
975  table->fHasbg = hasbg;
976  fPNext = TableDimensions(table, 0);
977  x1 = table->fMaxW[0] + indent + obstacle;
978  x2 = table->fMinW[0] + indent;
979  SETMAX(max, x1);
980  SETMAX(min, x2);
981  x1 = indent + obstacle;
982  x2 = indent;
983  if (fPNext && fPNext->fType == Html_EndTABLE) fPNext = fPNext->fPNext;
984  break;
985  }
986 
987  case Html_UL:
988  case Html_OL:
989  indent += HTML_INDENT;
990  x1 = indent + obstacle;
991  x2 = indent;
992  break;
993 
994  case Html_EndUL:
995  case Html_EndOL:
996  indent -= HTML_INDENT;
997  if (indent < 0) indent = 0;
998  x1 = indent + obstacle;
999  x2 = indent;
1000  break;
1001 
1002  case Html_BLOCKQUOTE:
1003  indent += 2 * HTML_INDENT;
1004  x1 = indent + obstacle;
1005  x2 = indent;
1006  break;
1007 
1008  case Html_EndBLOCKQUOTE:
1009  indent -= 2 * HTML_INDENT;
1010  if (indent < 0) indent = 0;
1011  x1 = indent + obstacle;
1012  x2 = indent;
1013  break;
1014 
1015  case Html_APPLET:
1016  case Html_INPUT:
1017  case Html_SELECT:
1018  case Html_EMBED:
1019  case Html_TEXTAREA: {
1020  TGHtmlInput *input = (TGHtmlInput *) p;
1021  x1 += input->fW + input->fPadLeft;
1022  if (p->fStyle.fFlags & STY_Preformatted) {
1023  x3 += input->fW + input->fPadLeft;
1024  SETMAX(min, x3);
1025  SETMAX(max, x1);
1026  x2 += input->fW + input->fPadLeft;
1027  } else {
1028  SETMAX(min, indent + input->fW);
1029  SETMAX(max, x1);
1030  x2 = indent;
1031  }
1032  break;
1033  }
1034 
1035  case Html_BR:
1036  case Html_P:
1037  case Html_EndP:
1038  case Html_DIV:
1039  case Html_EndDIV:
1040  case Html_H1:
1041  case Html_EndH1:
1042  case Html_H2:
1043  case Html_EndH2:
1044  case Html_H3:
1045  case Html_EndH3:
1046  case Html_H4:
1047  case Html_EndH4:
1048  case Html_H5:
1049  case Html_H6:
1050  x1 = indent + obstacle;
1051  x2 = indent;
1052  break;
1053 
1054  case Html_EndTD:
1055  case Html_EndTH:
1056  case Html_CAPTION:
1057  case Html_EndTABLE:
1058  case Html_TD:
1059  case Html_TR:
1060  case Html_TH:
1061  case Html_EndTR:
1062  go = 0;
1063  break;
1064 
1065  default:
1066  break;
1067  }
1068 
1069  if (!go) break;
1070  }
1071 
1072  *pMin = min;
1073  *pMax = max;
1074 
1075  return p;
1076 }
1077 
1078 
1079 // Vertical alignments:
1080 
1081 #define VAlign_Unknown 0
1082 #define VAlign_Top 1
1083 #define VAlign_Bottom 2
1084 #define VAlign_Center 3
1085 #define VAlign_Baseline 4
1086 
1087 
1088 ////////////////////////////////////////////////////////////////////////////////
1089 /// Return the vertical alignment specified by the given element.
1090 
1092 {
1093  const char *z;
1094  int rc;
1095 
1096  z = MarkupArg("valign", 0);
1097  if (z == 0) {
1098  rc = dflt;
1099  } else if (strcasecmp(z, "top") == 0) {
1100  rc = VAlign_Top;
1101  } else if (strcasecmp(z, "bottom") == 0) {
1102  rc = VAlign_Bottom;
1103  } else if (strcasecmp(z, "center") == 0) {
1104  rc = VAlign_Center;
1105  } else if (strcasecmp(z, "baseline") == 0) {
1106  rc = VAlign_Baseline;
1107  } else{
1108  rc = dflt;
1109  }
1110 
1111  return rc;
1112 }
1113 
1114 ////////////////////////////////////////////////////////////////////////////////
1115 /// Do all layout for a single table. Return the </table> element or
1116 /// NULL if the table is unterminated.
1117 
1119 {
1120  TGHtmlElement *pEnd1; // The </table> element
1121  TGHtmlElement *p; // For looping thru elements of the table
1122  TGHtmlElement *fPNext; // Next element in the loop
1123  TGHtmlElement *pCaption=0; // Start of the caption text. The <caption>
1124  // TGHtmlElement *pEndCaption; // End of the caption. The </caption>
1125  int width; // Width of the table as drawn
1126  int cellSpacing; // Value of cellspacing= parameter to <table>
1127  int cellPadding; // Value of cellpadding= parameter to <table>
1128  int tbw; // Width of the 3D border around the whole table
1129  int cbw; // Width of the 3D border around a cell
1130  int pad; // cellPadding + borderwidth
1131  const char *z; // A string
1132  int left_margin; // The left edge of space available for drawing
1133  int lineWidth; // Total horizontal space available for drawing
1134  int specWidth; // Total horizontal drawing width per width= attr
1135  int separation; // Distance between content of columns (or rows)
1136  int i; // Loop counter
1137  int n; // Number of columns
1138  int btm; // Bottom edge of previous row
1139  int iRow; // Current row number
1140  int iCol; // Current column number
1141  int colspan; // Number of columns spanned by current cell
1142  int vspace; // Value of the vspace= parameter to <table>
1143  // int hspace; // Value of the hspace= parameter to <table>
1144  int rowBottom; // Bottom edge of content in the current row
1145  int defaultVAlign; // Default vertical alignment for the current row
1146  const char *zAlign; // Value of the ALIGN= attribute of the <TABLE>
1147 #define N (HTML_MAX_COLUMNS+1)
1148  int y[N]={0}; // Top edge of each cell's content
1149  int x[N]={0}; // Left edge of each cell's content
1150  int w[N]={0}; // Width of each cell's content
1151  int ymax[N]={0}; // Bottom edge of cell's content if valign=top
1152  TGHtmlElement *apElem[N]={0}; // The <td> or <th> for each cell in a row
1153  // int firstRow[N]={0}; // First row on which a cell appears
1154  int lastRow[N]={0}; // Row to which each cell span's
1155  int valign[N]={0}; // Vertical alignment for each cell
1156  TGHtmlLayoutContext savedContext; // Saved copy of the original pLC
1157  TGHtmlLayoutContext cellContext; // Used to render a single cell
1158 #ifdef TABLE_TRIM_BLANK
1159  extern int HtmlLineWasBlank;
1160 #endif // TABLE_TRIM_BLANK
1161 
1162  if (pTable == 0 || pTable->fType != Html_TABLE) return pTable;
1163 
1165  TRACE(HtmlTrace_Table2, ("Starting TableLayout() at %s\n",
1166  fHtml->GetTokenName(pTable)));
1167 
1168  for (i=0;i<N;i++) ymax[i]=0;
1169 
1170  // Figure how much horizontal space is available for rendering
1171  // this table. Store the answer in lineWidth. left_margin is
1172  // the left-most X coordinate of the table. btm stores the top-most
1173  // Y coordinate.
1174 
1175  ComputeMargins(&left_margin, &btm, &lineWidth);
1176 
1177  TRACE(HtmlTrace_Table2, ("...btm=%d left=%d width=%d\n",
1178  btm, left_margin, lineWidth));
1179 
1180  // figure out how much space the table wants for each column,
1181  // and in total..
1182  pEnd1 = fHtml->TableDimensions(pTable, lineWidth);
1183 
1184  // If we don't have enough horizontal space to accomodate the minimum table
1185  // width, then try to move down past some obstruction (such as an
1186  // <IMG ALIGN=LEFT>) to give us more room.
1187 
1188  if (lineWidth < pTable->fMinW[0]) {
1189  WidenLine(pTable->fMinW[0], &left_margin, &btm, &lineWidth);
1190 
1191  TRACE(HtmlTrace_Table2, ("Widen to btm=%d left=%d width=%d\n",
1192  btm, left_margin, lineWidth));
1193  }
1194  savedContext = *this;
1195 
1196  // Figure out how wide to draw the table
1197  z = pTable->MarkupArg("width", 0);
1198  if (z) {
1199  int len = strlen(z);
1200  if (len > 0 && z[len-1] == '%') {
1201  specWidth = (atoi(z) * lineWidth) / 100;
1202  } else {
1203  specWidth = atoi(z);
1204  }
1205  } else {
1206  specWidth = lineWidth;
1207  }
1208  if (specWidth < pTable->fMinW[0]) {
1209  width = pTable->fMinW[0];
1210  } else if (specWidth <= pTable->fMaxW[0]) {
1211  width = specWidth;
1212  } else {
1213  width = pTable->fMaxW[0];
1214  }
1215 
1216  // Compute the width and left edge position of every column in
1217  // the table
1218 
1219  z = pTable->MarkupArg("cellpadding", 0);
1220  cellPadding = z ? atoi(z) : DFLT_CELLPADDING;
1221  cellSpacing = fHtml->CellSpacing(pTable);
1222 
1223  z = pTable->MarkupArg("vspace", 0);
1224  vspace = z ? atoi(z) : DFLT_VSPACE;
1225 
1226  z = pTable->MarkupArg("hspace", 0);
1227  // hspace = z ? atoi(z) : DFLT_HSPACE;
1228 
1229 #ifdef DEBUG
1231  cellPadding = 5;
1232  cellSpacing = 2;
1233  if (vspace < 2) vspace = 2;
1234  // if (hspace < 2) hspace = 2;
1235  }
1236 #endif
1237 
1238  tbw = pTable->fBorderWidth;
1239  cbw = (tbw > 0);
1240  pad = cellPadding + cbw;
1241  separation = cellSpacing + 2 * pad;
1242  x[1] = left_margin + tbw + cellSpacing + pad;
1243 
1244  n = pTable->fNCol;
1245  if (n <= 0 || pTable->fMaxW[0] <= 0) {
1246  // Abort if the table has no columns at all or if the total width
1247  // of the table is zero or less.
1248  return pEnd1;
1249  }
1250 
1251  zAlign = pTable->MarkupArg("align", "");
1252  if (width <= lineWidth) {
1253  int align = pTable->fStyle.fAlign;
1254  if (align == ALIGN_Right || strcasecmp(zAlign, "right") == 0) {
1255  x[1] += lineWidth - width;
1256  } else if (align == ALIGN_Center && strcasecmp(zAlign, "left") != 0) {
1257  x[1] += (lineWidth - width) / 2;
1258  }
1259  }
1260 
1261  if (width == pTable->fMaxW[0]) {
1262  w[1] = pTable->fMaxW[1];
1263  for (i = 2; i <= n; i++) {
1264  w[i] = pTable->fMaxW[i];
1265  x[i] = x[i-1] + w[i-1] + separation;
1266  }
1267  } else if (width > pTable->fMaxW[0]) {
1268  int *tmaxW = pTable->fMaxW;
1269  double scale = ((double) width) / (double) tmaxW[0];
1270  w[1] = (int) (tmaxW[1] * scale);
1271  for (i = 2; i <= n; i++) {
1272  w[i] = (int) (tmaxW[i] * scale);
1273  x[i] = x[i-1] + w[i-1] + separation;
1274  }
1275  } else if (width > pTable->fMinW[0]) {
1276  float scale;
1277  int *tminW = pTable->fMinW;
1278  int *tmaxW = pTable->fMaxW;
1279  scale = (double) (width - tminW[0]) / (double) (tmaxW[0] - tminW[0]);
1280  w[1] = (int) (tminW[1] + (tmaxW[1] - tminW[1]) * scale);
1281  for (i = 2; i <= n; i++) {
1282  w[i] = (int) (tminW[i] + (tmaxW[i] - tminW[i]) * scale);
1283  x[i] = x[i-1] + w[i-1] + separation;
1284  }
1285  } else {
1286  w[1] = pTable->fMinW[1];
1287  for (i = 2; i <= n; i++) {
1288  w[i] = pTable->fMinW[i];
1289  x[i] = x[i-1] + w[i-1] + separation;
1290  }
1291  }
1292  w[n] = width - ((x[n] - x[1]) + 2 * (tbw + pad + cellSpacing));
1293 
1294  // Add notation to the pTable structure so that we will know where
1295  // to draw the outer box around the outside of the table.
1296 
1297  btm += vspace;
1298  pTable->fY = btm;
1299  pTable->fX = x[1] - (tbw + cellSpacing + pad);
1300  pTable->fW = width;
1301  SETMAX(fMaxX, pTable->fX + pTable->fW);
1302  btm += tbw + cellSpacing;
1303 
1304  // Begin rendering rows of the table
1305  for (i = 1; i <= n; i++) {
1306  // firstRow[i] = 0;
1307  lastRow[i] = 0;
1308  apElem[i] = 0;
1309  }
1310  p = pTable->fPNext;
1311  rowBottom = btm;
1312  for (iRow = 1; iRow <= pTable->fNRow; iRow++) {
1313 
1314  TRACE(HtmlTrace_Table2, ("Row %d: btm=%d\n",iRow,btm));
1315 
1316  // Find the start of the next row. Keep an eye out for the caption
1317  // while we search
1318  while (p && p->fType != Html_TR) {
1319  if (p->fType == Html_CAPTION) {
1320  pCaption = p;
1321  while (p && p != pEnd1 && p->fType != Html_EndCAPTION) p = p->fPNext;
1322  // pEndCaption = p;
1323  }
1324 
1325  TRACE(HtmlTrace_Table3, ("Skipping token %s\n", fHtml->GetTokenName(p)));
1326 
1327  if (p) p = p->fPNext;
1328  }
1329  if (p == 0) break;
1330 
1331  // Record default vertical alignment flag for this row
1332  defaultVAlign = p->GetVerticalAlignment(VAlign_Center);
1333 
1334  // Find every new cell on this row
1335  for (iCol = 1; iCol <= pTable->fNCol && iCol <= HTML_MAX_COLUMNS; iCol++) {
1336  if (lastRow[iCol] < iRow) ymax[iCol] = 0;
1337  }
1338  iCol = 0;
1339  for (p = p->fPNext; p && p->fType != Html_TR && p != pEnd1; p = fPNext) {
1340  fPNext = p->fPNext;
1341 
1342  TRACE(HtmlTrace_Table3, ("Processing token %s\n", fHtml->GetTokenName(p)));
1343 
1344  switch (p->fType) {
1345  case Html_TD:
1346  case Html_TH:
1347  // Find the column number for this cell. Be careful to skip
1348  // columns which extend down to this row from prior rows
1349  do {
1350  iCol++;
1351  } while (iCol <= HTML_MAX_COLUMNS && lastRow[iCol] >= iRow);
1352 
1354  ("Column %d: x=%d w=%d\n",iCol,x[iCol],w[iCol]));
1355 
1356  // Process the new cell. (Cells beyond the maximum number of
1357  // cells are simply ignored.)
1358  if (iCol <= HTML_MAX_COLUMNS) {
1359  TGHtmlCell *cell = (TGHtmlCell *) p;
1360  apElem[iCol] = p;
1361  fPNext = cell->fPEnd;
1362  if (cell->fRowspan == 0) {
1363  lastRow[iCol] = pTable->fNRow;
1364  } else {
1365  lastRow[iCol] = iRow + cell->fRowspan - 1;
1366  }
1367  // firstRow[iCol] = iRow;
1368 
1369  // Set vertical alignment flag for this cell
1370  valign[iCol] = p->GetVerticalAlignment(defaultVAlign);
1371 
1372  // Render cell contents and record the height
1373  y[iCol] = btm + pad;
1374  cellContext.fHtml = fHtml;
1375  cellContext.fPStart = p->fPNext;
1376  cellContext.fPEnd = fPNext;
1377  cellContext.fHeadRoom = 0;
1378  cellContext.fTop = y[iCol];
1379  cellContext.fBottom = y[iCol];
1380  cellContext.fLeft = x[iCol];
1381  cellContext.fRight = 0;
1382  cellContext.fPageWidth = x[iCol] + w[iCol];
1383  colspan = cell->fColspan;
1384  if (colspan == 0) {
1385  for (i = iCol + 1;
1386  i <= pTable->fNCol && i <= HTML_MAX_COLUMNS; i++) {
1387  cellContext.fPageWidth += w[i] + separation;
1388  lastRow[i] = lastRow[iCol];
1389  }
1390  } else if (colspan > 1) {
1391  for (i = iCol + 1;
1392  i < iCol + colspan && i <= HTML_MAX_COLUMNS; i++) {
1393  cellContext.fPageWidth += w[i] + separation;
1394  lastRow[i] = lastRow[iCol];
1395  }
1396  }
1397  cellContext.fMaxX = 0;
1398  cellContext.fMaxY = 0;
1399  cellContext.fLeftMargin = 0;
1400  cellContext.fRightMargin = 0;
1401  cellContext.LayoutBlock();
1402 #ifdef TABLE_TRIM_BLANK
1403  // Cancel any trailing vertical whitespace caused
1404  // by break markup
1405  if (HtmlLineWasBlank) {
1406  cellContext.fMaxY -= cellContext.headRoom;
1407  }
1408 #endif // TABLE_TRIM_BLANK
1409  ymax[iCol] = cellContext.fMaxY;
1410  SETMAX(ymax[iCol], y[iCol]);
1411  cellContext.ClearMarginStack(&cellContext.fLeftMargin);
1412  cellContext.ClearMarginStack(&cellContext.fRightMargin);
1413 
1414  // Set coordinates of the cell border
1415  cell->fX = x[iCol] - pad;
1416  cell->fY = btm;
1417  cell->fW = cellContext.fPageWidth + 2 * pad - x[iCol];
1418 
1420  ("Column %d top=%d bottom=%d h=%d left=%d w=%d\n",
1421  iCol, y[iCol], ymax[iCol], ymax[iCol]-y[iCol],
1422  cell->fX, cell->fW));
1423 
1424  // Advance the column counter for cells spaning multiple columns
1425  if (colspan > 1) {
1426  iCol += colspan - 1;
1427  } else if (colspan == 0) {
1428  iCol = HTML_MAX_COLUMNS + 1;
1429  }
1430  }
1431  break;
1432 
1433  case Html_CAPTION:
1434  // Gotta remember where the caption is so we can render it
1435  // at the end
1436  pCaption = p;
1437  while (fPNext && fPNext != pEnd1 && fPNext->fType != Html_EndCAPTION) {
1438  fPNext = fPNext->fPNext;
1439  }
1440  // pEndCaption = fPNext;
1441  break;
1442  }
1443  }
1444 
1445  // Figure out how high to make this row.
1446  for (iCol = 1; iCol <= pTable->fNCol; iCol++) {
1447  if (lastRow[iCol] == iRow || iRow == pTable->fNRow) {
1448  SETMAX(rowBottom, ymax[iCol]);
1449  }
1450  }
1451 
1452  TRACE(HtmlTrace_Table2, ("Total row height: %d..%d -> %d\n",
1453  btm,rowBottom,rowBottom-btm));
1454 
1455  // Position every cell whose bottom edge ends on this row
1456  for (iCol = 1; iCol <= pTable->fNCol; iCol++) {
1457  int dy = 0; // Extra space at top of cell used for vertical alignment
1458  TGHtmlCell *apCell = (TGHtmlCell *) apElem[iCol];
1459 
1460  // Skip any unused cells or cells that extend down thru
1461  // subsequent rows
1462  if (apElem[iCol] == 0 ||
1463  (iRow != pTable->fNRow && lastRow[iCol] > iRow)) continue;
1464 
1465  // Align the contents of the cell vertically.
1466  switch (valign[iCol]) {
1467  case VAlign_Unknown:
1468  case VAlign_Center:
1469  dy = (rowBottom - ymax[iCol])/2;
1470  break;
1471  case VAlign_Top:
1472  case VAlign_Baseline:
1473  dy = 0;
1474  break;
1475  case VAlign_Bottom:
1476  dy = rowBottom - ymax[iCol];
1477  break;
1478  }
1479  if (dy) {
1480  TGHtmlElement *pLast = apCell->fPEnd;
1481 
1482  TRACE(HtmlTrace_Table3, ("Delta column %d by %d\n",iCol,dy));
1483 
1484  fHtml->MoveVertically(apElem[iCol]->fPNext, pLast, dy);
1485  }
1486 
1487  // Record the height of the cell so that the border can be drawn
1488  apCell->fH = rowBottom + pad - apCell->fY;
1489  apElem[iCol] = 0;
1490  }
1491 
1492  // Update btm to the height of the row we just finished setting
1493  btm = rowBottom + pad + cellSpacing;
1494  }
1495 
1496  btm += tbw;
1497  pTable->fH = btm - pTable->fY;
1498  SETMAX(fMaxY, btm);
1499  fBottom = btm + vspace;
1500 
1501  // Render the caption, if there is one
1502  if (pCaption) {
1503  }
1504 
1505  // Whenever we do any table layout, we need to recompute all the
1506  // TGHtmlBlocks. The following statement forces this.
1507  fHtml->ResetBlocks(); // fHtml->firstBlock = fHtml->lastBlock = 0;
1508 
1509  // Adjust the context for text that wraps around the table, if
1510  // requested by an ALIGN=RIGHT or ALIGN=LEFT attribute.
1511 
1512  if (strcasecmp(zAlign, "left") == 0) {
1513  savedContext.fMaxX = fMaxX;
1514  savedContext.fMaxY = fMaxY;
1515  *this = savedContext;
1516  PushMargin(&fLeftMargin, pTable->fW + 2, pTable->fY + pTable->fH + 2, 0);
1517  } else if (strcasecmp(zAlign, "right") == 0) {
1518  savedContext.fMaxX = fMaxX;
1519  savedContext.fMaxY = fMaxY;
1520  *this = savedContext;
1521  PushMargin(&fRightMargin, pTable->fW + 2, pTable->fY + pTable->fH + 2, 0);
1522  }
1523 
1524  // All done
1525 
1527  "Done with TableLayout(). x=%d y=%d w=%d h=%d Return %s\n",
1528  pTable->fX, pTable->fY, pTable->fW, pTable->fH,
1529  fHtml->GetTokenName(pEnd1)));
1531 
1532  return pEnd1;
1533 }
1534 
1535 ////////////////////////////////////////////////////////////////////////////////
1536 /// Move all elements in the given list vertically by the amount dy
1537 ///
1538 /// p - First element to move
1539 /// pLast1 - Last element. Do move this one
1540 /// dy - Amount by which to move
1541 
1543 {
1544  if (dy == 0) return;
1545 
1546  while (p && p != pLast1) {
1547  switch (p->fType) {
1548  case Html_A:
1549  ((TGHtmlAnchor *)p)->fY += dy;
1550  break;
1551 
1552  case Html_Text:
1553  ((TGHtmlTextElement *)p)->fY += dy;
1554  break;
1555 
1556  case Html_LI:
1557  ((TGHtmlLi *)p)->fY += dy;
1558  break;
1559 
1560  case Html_TD:
1561  case Html_TH:
1562  ((TGHtmlCell *)p)->fY += dy;
1563  break;
1564 
1565  case Html_TABLE:
1566  ((TGHtmlTable *)p)->fY += dy;
1567  break;
1568 
1569  case Html_IMG:
1570  ((TGHtmlImageMarkup *)p)->fY += dy;
1571  break;
1572 
1573  case Html_INPUT:
1574  case Html_SELECT:
1575  case Html_APPLET:
1576  case Html_EMBED:
1577  case Html_TEXTAREA:
1578  ((TGHtmlInput *)p)->fY += dy;
1579  break;
1580 
1581  default:
1582  break;
1583  }
1584  p = p->fPNext;
1585  }
1586 }
Html_32_t fY
Definition: TGHtml.h:362
#define ColReq(A, B)
#define VAlign_Center
TImage * fBgImage
Definition: TGHtml.h:395
TGString * TableText(TGHtmlTable *pTable, int flags)
Return text and images from a table as lists.
#define ColMin(A, B)
TGHtml * fHtml
Definition: TGHtml.h:794
Html_u16_t fNRow
Definition: TGHtml.h:361
#define IMAGE_ALIGN_Left
Definition: TGHtml.h:566
int fHasbg
Definition: TGHtml.h:370
#define HtmlTrace_Table5
Definition: TGHtml.h:89
#define DFLT_CELLSPACING_FLAT
Definition: TGHtmlTable.cxx:40
Html_32_t fY
Definition: TGHtml.h:390
#define MAX(A, B)
Definition: TGHtmlTable.cxx:47
TH1 * h
Definition: legend2.C:5
void LayoutBlock()
Do as much layout as possible on the block of text defined by the HtmlLayoutContext.
char * fZText
Definition: TGHtml.h:1168
#define LARGE_NUMBER
Definition: TGHtml.h:1345
#define TRACE(Flag, Args)
Definition: TGHtml.h:120
#define ALIGN_Center
Definition: TGHtml.h:210
virtual int GetVerticalAlignment(int dflt)
Definition: TGHtml.h:258
#define HTML_INDENT
Definition: TGHtml.h:753
int fMaxW[HTML_MAX_COLUMNS+1]
Definition: TGHtml.h:367
#define N
SHtmlMargin_t * fLeftMargin
Definition: TGHtml.h:804
Html_16_t fX
Definition: TGHtml.h:388
TImage * fBgImage
Definition: TGHtml.h:369
TGHtmlElement * MinMax(TGHtmlElement *p, int *pMin, int *pMax, int lineWidth, int hasbg)
Given a list of elements, compute the minimum and maximum width needed to render the list...
#define SETMAX(A, B)
Definition: TGHtmlTable.cxx:46
TGHtmlElement * TableLayout(TGHtmlTable *p)
Do all layout for a single table.
#define HtmlTrace_Table1
Definition: TGHtml.h:85
#define STY_Preformatted
Definition: TGHtml.h:233
#define HtmlTrace_Table4
Definition: TGHtml.h:88
#define COLOR_Background
Definition: TGHtml.h:200
Html_16_t fW
Definition: TGHtml.h:545
Html_16_t fColspan
Definition: TGHtml.h:387
#define HtmlTrace_Table3
Definition: TGHtml.h:87
TGHtmlElement * fPNext
Definition: TGHtml.h:261
#define TRACE_POP(Flag)
Definition: TGHtml.h:122
Html_32_t fH
Definition: TGHtml.h:363
static const double x2[5]
Html_u8_t fBorderWidth
Definition: TGHtml.h:359
Double_t x[n]
Definition: legend1.C:17
Html_u8_t fNCol
Definition: TGHtml.h:360
virtual const char * MarkupArg(const char *, const char *)
Definition: TGHtml.h:254
void StringHW(const char *str, int *h, int *w)
Return the height and width of string.
Definition: TGHtmlTable.cxx:77
unsigned int fBgcolor
Definition: TGHtml.h:148
TGHtmlElement * FindEndNest(TGHtmlElement *sp, int en, TGHtmlElement *lp)
Find End tag en, but ignore intervening begin/end tag pairs.
TString & Append(const char *cs)
Definition: TString.h:495
int fMaxY
Definition: TGHtml.h:1262
int CellSpacing(TGHtmlElement *pTable)
Return the appropriate cell spacing for the given table.
Definition: TGHtmlTable.cxx:53
Html_u8_t fAlign
Definition: TGHtml.h:539
TGHtmlElement * fPPrev
Definition: TGHtml.h:262
#define VAlign_Top
#define DFLT_VSPACE
Definition: TGHtmlTable.cxx:43
void MoveVertically(TGHtmlElement *p, TGHtmlElement *pLast, int dy)
Move all elements in the given list vertically by the amount dy.
int HtmlTraceMask
Definition: TGHtml.cxx:60
TGHtmlElement * fPEnd
Definition: TGHtml.h:796
float ymax
Definition: THbookFile.cxx:93
#define HtmlTrace_Table6
Definition: TGHtml.h:90
#define HTML_RELIEF_SUNKEN
Definition: TGHtml.h:51
#define DFLT_CELLPADDING
Definition: TGHtmlTable.cxx:41
SHtmlStyle_t fStyle
Definition: TGHtml.h:263
Html_32_t fH
Definition: TGHtml.h:391
#define HtmlTrace_Table2
Definition: TGHtml.h:86
Html_u16_t fW
Definition: TGHtml.h:597
Html_u8_t fPadLeft
Definition: TGHtml.h:598
char * GetTokenName(TGHtmlElement *p)
Returns token name of html element p.
void AppendArglist(TGString *str, TGHtmlMarkupElement *pElem)
Append all the arguments of the given markup to the given TGString.
TGHtmlTable * fPTable
Definition: TGHtml.h:392
Html_16_t fRowspan
Definition: TGHtml.h:386
Html_16_t fX
Definition: TGHtml.h:364
int fTableRelief
Definition: TGHtml.h:1256
Html_u8_t fType
Definition: TGHtml.h:264
#define VAlign_Baseline
#define HTML_NewLine
Definition: TGHtml.h:275
const char * GetString() const
Definition: TGString.h:40
unsigned int fFlags
Definition: TGHtml.h:150
virtual int GetVerticalAlignment(int dflt)
Return the vertical alignment specified by the given element.
static const double x1[5]
TText * text
#define DFLT_CELLSPACING_3D
Definition: TGHtmlTable.cxx:39
int fMaxX
Definition: TGHtml.h:1262
TGHtmlElement * fPEnd
Definition: TGHtml.h:368
TGHtmlElement * TableDimensions(TGHtmlTable *pStart, int lineWidth)
pStart points to a
Html_16_t fW
Definition: TGHtml.h:296
Double_t y[n]
Definition: legend1.C:17
#define HTML_MAX_COLUMNS
Definition: TGHtml.h:342
Html_16_t fW
Definition: TGHtml.h:389
#define STY_NoBreak
Definition: TGHtml.h:236
you should not use this method at all Int_t Int_t z
Definition: TRolke.cxx:630
#define HTML_RELIEF_RAISED
Definition: TGHtml.h:52
int fMinW[HTML_MAX_COLUMNS+1]
Definition: TGHtml.h:366
TGHtmlElement * fPEnd
Definition: TGHtml.h:394
#define TRACE_PUSH(Flag)
Definition: TGHtml.h:121
Html_16_t fW
Definition: TGHtml.h:365
Html_16_t fCount
Definition: TGHtml.h:266
TGHtmlElement * fPStart
Definition: TGHtml.h:795
#define VAlign_Bottom
#define DFLT_BORDER
Definition: TGHtmlTable.cxx:38
#define TRACE_INDENT
Definition: TGHtml.h:119
#define snprintf
Definition: civetweb.c:822
#define ALIGN_Right
Definition: TGHtml.h:209
unsigned int fAlign
Definition: TGHtml.h:147
void ClearMarginStack(SHtmlMargin_t **ppMargin)
Clear a margin stack to reclaim memory.
#define IMAGE_ALIGN_Right
Definition: TGHtml.h:567
Html_16_t fW
Definition: TGHtml.h:308
virtual const char * MarkupArg(const char *tag, const char *zDefault)
Lookup an argument in the given markup with the name given.
Int_t GetLength() const
Definition: TGString.h:39
const Int_t n
Definition: legend1.C:16
SHtmlMargin_t * fRightMargin
Definition: TGHtml.h:805
TGHtmlElement * fPRow
Definition: TGHtml.h:393
#define VAlign_Unknown
Html_u8_t fFlags
Definition: TGHtml.h:265
int fTableBorderMin
Definition: TGHtml.h:1246
static const double x3[11]
const char * Data() const
Definition: TString.h:345