Logo ROOT  
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 <cstdlib>
29#include <cstring>
30#include <cctype>
31#include <cmath>
32
33#include "TGHtml.h"
34#include "snprintf.h"
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
77void 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 (!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;
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;
446 }
447#endif
448
449 separation = cellSpacing + 2 * (cellPadding + cbw);
450 margin = tbw + cellSpacing + cbw + cellPadding;
451
452 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 (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 = "";
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) {
640 printf("ColMin(%d,%d) = %d\n", i, j, ColMin(i, j));
641 }
642 if (ColReq(i, j) > 0) {
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
751 const char *zSpace = "";
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
838 printf("Start with %s and ", GetTokenName(pStart));
839 printf("end with %s\n", GetTokenName(p));
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++) {
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
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: {
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: {
946 switch (image->fAlign) {
947 case IMAGE_ALIGN_Left:
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:
990 x1 = indent + obstacle;
991 x2 = indent;
992 break;
993
994 case Html_EndUL:
995 case Html_EndOL:
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 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}
double
Definition: Converters.cxx:939
#define h(i)
Definition: RSha256.hxx:106
static const double x2[5]
static const double x1[5]
static const double x3[11]
static void indent(ostringstream &buf, int indent_level)
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
#define N
#define VAlign_Top
#define DFLT_VSPACE
Definition: TGHtmlTable.cxx:43
#define VAlign_Bottom
#define DFLT_CELLSPACING_FLAT
Definition: TGHtmlTable.cxx:40
#define DFLT_CELLPADDING
Definition: TGHtmlTable.cxx:41
#define ColReq(A, B)
#define VAlign_Center
#define VAlign_Unknown
#define DFLT_BORDER
Definition: TGHtmlTable.cxx:38
#define SETMAX(A, B)
Definition: TGHtmlTable.cxx:46
#define MAX(A, B)
Definition: TGHtmlTable.cxx:47
#define VAlign_Baseline
#define ColMin(A, B)
#define DFLT_CELLSPACING_3D
Definition: TGHtmlTable.cxx:39
@ Html_H3
Definition: TGHtmlTokens.h:103
@ Html_EndH4
Definition: TGHtmlTokens.h:106
@ Html_FORM
Definition: TGHtmlTokens.h:93
@ Html_EndTH
Definition: TGHtmlTokens.h:179
@ Html_BLOCKQUOTE
Definition: TGHtmlTokens.h:61
@ Html_EndTABLE
Definition: TGHtmlTokens.h:173
@ Html_TEXTAREA
Definition: TGHtmlTokens.h:176
@ Html_TD
Definition: TGHtmlTokens.h:174
@ Html_EMBED
Definition: TGHtmlTokens.h:90
@ Html_LI
Definition: TGHtmlTokens.h:122
@ Html_EndBLOCKQUOTE
Definition: TGHtmlTokens.h:62
@ Html_CAPTION
Definition: TGHtmlTokens.h:66
@ Html_UL
Definition: TGHtmlTokens.h:188
@ Html_TABLE
Definition: TGHtmlTokens.h:172
@ Html_EndUL
Definition: TGHtmlTokens.h:189
@ Html_EndOL
Definition: TGHtmlTokens.h:144
@ Html_OPTION
Definition: TGHtmlTokens.h:145
@ Html_H2
Definition: TGHtmlTokens.h:101
@ Html_APPLET
Definition: TGHtmlTokens.h:50
@ Html_TH
Definition: TGHtmlTokens.h:178
@ Html_EndTD
Definition: TGHtmlTokens.h:175
@ Html_TR
Definition: TGHtmlTokens.h:182
@ Html_H6
Definition: TGHtmlTokens.h:109
@ Html_DIV
Definition: TGHtmlTokens.h:82
@ Html_Space
Definition: TGHtmlTokens.h:43
@ Html_EndH3
Definition: TGHtmlTokens.h:104
@ Html_SELECT
Definition: TGHtmlTokens.h:159
@ Html_H5
Definition: TGHtmlTokens.h:107
@ Html_Text
Definition: TGHtmlTokens.h:42
@ Html_H1
Definition: TGHtmlTokens.h:99
@ Html_EndDIV
Definition: TGHtmlTokens.h:83
@ Html_OL
Definition: TGHtmlTokens.h:143
@ Html_A
Definition: TGHtmlTokens.h:46
@ Html_P
Definition: TGHtmlTokens.h:147
@ Html_IMG
Definition: TGHtmlTokens.h:117
@ Html_EndCAPTION
Definition: TGHtmlTokens.h:67
@ Html_H4
Definition: TGHtmlTokens.h:105
@ Html_EndH1
Definition: TGHtmlTokens.h:100
@ Html_EndH2
Definition: TGHtmlTokens.h:102
@ Html_BR
Definition: TGHtmlTokens.h:65
@ Html_EndP
Definition: TGHtmlTokens.h:148
@ Html_EndPRE
Definition: TGHtmlTokens.h:153
@ Html_PRE
Definition: TGHtmlTokens.h:152
@ Html_INPUT
Definition: TGHtmlTokens.h:118
@ Html_EndTR
Definition: TGHtmlTokens.h:183
int HtmlTraceMask
Definition: TGHtml.cxx:66
#define HtmlTrace_Table1
Definition: TGHtml.h:86
#define TRACE_PUSH(Flag)
Definition: TGHtml.h:122
#define HTML_MAX_COLUMNS
Definition: TGHtml.h:343
#define ALIGN_Right
Definition: TGHtml.h:210
#define HTML_RELIEF_SUNKEN
Definition: TGHtml.h:52
#define STY_NoBreak
Definition: TGHtml.h:237
#define COLOR_Background
Definition: TGHtml.h:201
#define TRACE_POP(Flag)
Definition: TGHtml.h:123
#define LARGE_NUMBER
Definition: TGHtml.h:1354
#define HTML_RELIEF_RAISED
Definition: TGHtml.h:53
#define HTML_NewLine
Definition: TGHtml.h:276
#define HtmlTrace_Table2
Definition: TGHtml.h:87
#define HtmlTrace_Table3
Definition: TGHtml.h:88
#define TRACE_INDENT
Definition: TGHtml.h:120
#define ALIGN_Center
Definition: TGHtml.h:211
#define HTML_INDENT
Definition: TGHtml.h:754
#define IMAGE_ALIGN_Right
Definition: TGHtml.h:568
#define HtmlTrace_Table5
Definition: TGHtml.h:90
#define IMAGE_ALIGN_Left
Definition: TGHtml.h:567
#define HtmlTrace_Table4
Definition: TGHtml.h:89
#define STY_Preformatted
Definition: TGHtml.h:234
#define HtmlTrace_Table6
Definition: TGHtml.h:91
#define TRACE(Flag, Args)
Definition: TGHtml.h:121
float ymax
Definition: THbookFile.cxx:95
#define snprintf
Definition: civetweb.c:1540
Html_32_t fH
Definition: TGHtml.h:392
TImage * fBgImage
Definition: TGHtml.h:396
Html_16_t fColspan
Definition: TGHtml.h:388
Html_16_t fX
Definition: TGHtml.h:389
Html_16_t fW
Definition: TGHtml.h:390
Html_16_t fRowspan
Definition: TGHtml.h:387
TGHtmlTable * fPTable
Definition: TGHtml.h:393
TGHtmlElement * fPEnd
Definition: TGHtml.h:395
Html_32_t fY
Definition: TGHtml.h:391
TGHtmlElement * fPRow
Definition: TGHtml.h:394
Html_u8_t fFlags
Definition: TGHtml.h:266
Html_u8_t fType
Definition: TGHtml.h:265
virtual int GetVerticalAlignment(int dflt)
Definition: TGHtml.h:259
SHtmlStyle_t fStyle
Definition: TGHtml.h:264
virtual const char * MarkupArg(const char *, const char *)
Definition: TGHtml.h:255
TGHtmlElement * fPPrev
Definition: TGHtml.h:263
Html_16_t fCount
Definition: TGHtml.h:267
TGHtmlElement * fPNext
Definition: TGHtml.h:262
Html_16_t fW
Definition: TGHtml.h:546
Html_u8_t fAlign
Definition: TGHtml.h:540
Html_u16_t fW
Definition: TGHtml.h:598
Html_u8_t fPadLeft
Definition: TGHtml.h:599
TGHtmlElement * fPStart
Definition: TGHtml.h:796
void ComputeMargins(int *pX, int *pY, int *pW)
Compute the current margins for layout.
TGHtmlElement * TableLayout(TGHtmlTable *p)
Do all layout for a single table.
void LayoutBlock()
Do as much layout as possible on the block of text defined by the HtmlLayoutContext.
SHtmlMargin_t * fRightMargin
Definition: TGHtml.h:806
void PushMargin(SHtmlMargin_t **ppMargin, int indent, int bottom, int tag)
Push a new margin onto the given margin stack.
void ClearMarginStack(SHtmlMargin_t **ppMargin)
Clear a margin stack to reclaim memory.
TGHtml * fHtml
Definition: TGHtml.h:795
void WidenLine(int reqWidth, int *pX, int *pY, int *pW)
Move past obstacles until a linewidth of reqWidth is obtained, or until all obstacles are cleared.
TGHtmlElement * fPEnd
Definition: TGHtml.h:797
SHtmlMargin_t * fLeftMargin
Definition: TGHtml.h:805
virtual int GetVerticalAlignment(int dflt)
Return the vertical alignment specified by the given element.
virtual const char * MarkupArg(const char *tag, const char *zDefault)
Lookup an argument in the given markup with the name given.
Html_16_t fW
Definition: TGHtml.h:309
Html_u8_t fBorderWidth
Definition: TGHtml.h:360
int fHasbg
Definition: TGHtml.h:371
int fMinW[HTML_MAX_COLUMNS+1]
Definition: TGHtml.h:367
TGHtmlElement * fPEnd
Definition: TGHtml.h:369
Html_32_t fY
Definition: TGHtml.h:363
Html_16_t fX
Definition: TGHtml.h:365
Html_16_t fW
Definition: TGHtml.h:366
Html_u8_t fNCol
Definition: TGHtml.h:361
Html_u16_t fNRow
Definition: TGHtml.h:362
Html_32_t fH
Definition: TGHtml.h:364
int fMaxW[HTML_MAX_COLUMNS+1]
Definition: TGHtml.h:368
TImage * fBgImage
Definition: TGHtml.h:370
void MoveVertically(TGHtmlElement *p, TGHtmlElement *pLast, int dy)
Move all elements in the given list vertically by the amount dy.
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.
void StringHW(const char *str, int *h, int *w)
Return the height and width of string.
Definition: TGHtmlTable.cxx:77
int CellSpacing(TGHtmlElement *pTable)
Return the appropriate cell spacing for the given table.
Definition: TGHtmlTable.cxx:53
void AppendArglist(TGString *str, TGHtmlMarkupElement *pElem)
Append all the arguments of the given markup to the given TGString.
char * fZText
Definition: TGHtml.h:1176
TGString * TableText(TGHtmlTable *pTable, int flags)
Return text and images from a table as lists.
TGHtmlElement * FindEndNest(TGHtmlElement *sp, int en, TGHtmlElement *lp)
Find End tag en, but ignore intervening begin/end tag pairs.
char * GetTokenName(TGHtmlElement *p)
Returns token name of html element p.
void ResetBlocks()
Definition: TGHtml.h:978
TGHtmlElement * TableDimensions(TGHtmlTable *pStart, int lineWidth)
pStart points to a
int fTableRelief
Definition: TGHtml.h:1265
int fTableBorderMin
Definition: TGHtml.h:1255
TGString wraps a TString and adds some graphics routines like drawing, size of string on screen depen...
Definition: TGString.h:20
Int_t GetLength() const
Definition: TGString.h:29
const char * GetString() const
Definition: TGString.h:30
const char * Data() const
Definition: TString.h:369
TString & Append(const char *cs)
Definition: TString.h:564
TText * text
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
unsigned int fAlign
Definition: TGHtml.h:148
unsigned int fBgcolor
Definition: TGHtml.h:149
unsigned int fFlags
Definition: TGHtml.h:151