ide/Project: (#241) Seeing GCC warnings when building from IDE
[sdk] / extras / html / tables.ec
1 import "HTMLView"
2
3 class Column : struct
4 {
5    Column prev, next;
6    int w;         // Actual width for current rendering
7    int minW, lineW;
8    int rowSpan;
9    int width;
10    int desire;
11 };
12
13 void ComputeTable(Surface surface, Block table, int textPos, int * width, int * height, int maxW, int maxH, RenderFlags flags, int sy, int sx)
14 {
15    if(flags.minW || flags.lineW || flags.width)
16    {
17       Block row;
18       Column column;
19
20       int w = 0, h = 0;
21       int startX = sx;
22
23       // Pass 1: Figure out column widths
24
25       for(column = table.columns.first; column; column = column.next)
26       {
27          column.w = 0;
28
29          if(flags.minW)
30          {
31             column.minW = 0;
32             column.width = 0;
33          }
34          if(flags.lineW)
35          {
36             column.lineW = 0;
37          }
38          // Temporary variable:
39          column.rowSpan = 0;
40       }
41
42       for(row = table.subBlocks.first; row && row.type != TABLE; )
43       {
44          if(row.type == TR)
45          {
46             Block cell;
47             column = table.columns.first;
48             for(cell = row.subBlocks.first; cell; cell = cell.next)
49             {
50                if(cell.type == TD)
51                {
52                   int c;
53                   int centered = 0;
54                   int minW = 0, lineW = 0;
55                   Block block;
56                   int textPos = 0;
57                   // Disconnect the cell
58                   Block parent = cell.parent;
59                   Block next = cell.next;
60                   cell.parent = null;
61                   cell.next = null;
62
63                   while(column && column.rowSpan)
64                      column = column.next;
65
66                   if(!column)
67                   {
68                      column = Column { rowSpan = cell.rowSpan };
69                      // if(cell.rowSpan) Do proper thing if 0 rowSpan
70
71                      table.columns.Add(column);
72                   }
73
74                   // Process whole cell
75                   block = cell.subBlocks.first;
76                   for(;block;)
77                   {
78                      int w;
79                      Block nextCellBlock;
80                      int nextCellPos;
81
82                      // Minimum width for this column
83                      if(flags.minW)
84                      {
85                         if(cell.noWrap)
86                         {
87                            ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &w, MAXINT, 0, RenderFlags { lineW = true }, 0, null, null, null, true, sy, sx);
88                            /*if(cell.pWidth)
89                               w = Max(maxW * cell.pWidth / 100, w);*/
90                         }
91                         else
92                            ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &w, 0, 0, flags, 0, null, null, null, true, sy, sx);
93
94                         // Width specified absolute is minimum width
95                         /*
96                         if(cell.width)
97                            w = Max(cell.width, w);
98                         */
99
100                         minW = Max(minW, w);
101                      }
102                      if(flags.lineW)
103                      {
104                         // Width specified absolute will not extend
105                         if(maxW < cell.minW || cell.width)
106                         {
107                            //lineW = cell.minW;
108                            lineW = Max(cell.minW, cell.width);
109                            break;
110                         }
111                         else
112                         {
113                            ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &w, maxW, 0, RenderFlags { lineW = true }, 0, null, null, null, true, sy, sx);
114                            if(cell.pWidth)
115                               w = Max(maxW * cell.pWidth / 100, w);
116                            lineW = Max(lineW, w);
117                         }
118                      }
119
120                      textPos = nextCellPos;
121                      block = nextCellBlock;
122                   }
123
124                   cell.parent = parent;
125                   cell.next = next;
126
127                   minW += table.cellPadding * 2;
128                   lineW += table.cellPadding * 2;
129
130                   if(flags.minW)
131                      cell.minW = minW;
132                   if(flags.lineW)
133                      cell.lineW = lineW;
134
135                   // First only process non spanning cells
136                   if(cell.span == 1)
137                   {
138                      if(flags.minW)
139                      {
140                         column.width = Max(column.width, cell.width);
141                         column.minW = Max(column.minW, cell.minW);
142                      }
143                      if(flags.lineW)
144                      {
145                         column.lineW = Max(column.lineW, cell.lineW);
146                         column.minW = Max(column.minW, cell.minW);
147                      }
148                   }
149
150                   for(c = 0; c<cell.span && column; c++)
151                      column = column.next;
152                }
153             }
154
155             for(column = table.columns.first; column; column = column.next)
156                if(column.rowSpan)
157                   column.rowSpan--;
158
159             row = NextBlockUp(surface, row, null, 0);
160          }
161          else
162             row = NextBlock(surface, row, null, 0);
163       }
164
165       // Start with bare minimum
166       table.w = 0;
167       w = 0;
168       for(column = table.columns.first; column; column = column.next)
169       {
170          column.w = column.minW;
171          w += column.w;
172       }
173       if(w > table.w)
174          table.w = w;
175
176       //if(flags.width)
177       {
178          if(flags.lineW /*&& flags.width*/)
179          {
180             // Expand using lineW
181             if(!table.pWidth && !table.width)
182             {
183                int totalLineW = 0;
184
185                for(column = table.columns.first; column; column = column.next)
186                   column.rowSpan = 0;
187                for(row = table.subBlocks.first; row && row.type != TABLE; )
188                {
189                   if(row.type == TR)
190                   {
191                      Block cell;
192                      int rowLineW = 0;
193
194                      column = table.columns.first;
195
196                      for(cell = row.subBlocks.first; cell; cell = cell.next)
197                      {
198                         int c;
199                         int sumColW = 0;
200
201                         while(column && column.rowSpan)
202                            column = column.next;
203
204                         for(c = 0; c<cell.span && column; c++)
205                         {
206                            column.rowSpan = cell.rowSpan;
207                            sumColW += column.w;
208                            column = column.next;
209                         }
210                         rowLineW += Max(sumColW, cell.lineW);
211                      }
212                      totalLineW = Max(totalLineW, rowLineW);
213                      row = NextBlockUp(surface, row, null, 0);
214                   }
215                   else
216                      row = NextBlock(surface, row, null, 0);
217
218                   // MOVED THIS UP HERE
219                   for(column = table.columns.first; column; column = column.next)
220                      if(column.rowSpan) column.rowSpan--;
221                }
222
223                totalLineW = Min(maxW, totalLineW);
224                table.w = Max(table.w, totalLineW);
225                /*
226                for(column = table.columns.first; column; column = column.next)
227                   if(column.rowSpan) column.rowSpan--;
228                */
229             }
230          }
231
232          // Expand table more (only expand absolute if we're in that pass)
233          if(table.pWidth && (flags.width))
234          {
235             table.w = Max(table.w, maxW * table.pWidth / 100);
236          }
237          else if(table.width)
238          {
239             table.w = Max(table.w, table.width);
240          }
241
242          // Repartition the rest of the space in the columns according to column.lineW
243          if(w < table.w)
244          {
245             int needed = 0;
246
247             // Step 1: Weights how to distribute
248             for(column = table.columns.first; column; column = column.next)
249             {
250                column.rowSpan = 0;
251                column.desire = 0;
252             }
253             for(row = table.subBlocks.first; row && row.type != TABLE; )
254             {
255                if(row.type == TR)
256                {
257                   Block cell;
258                   Column columnStart = table.columns.first;
259
260                   for(cell = row.subBlocks.first; cell; cell = cell.next)
261                   {
262                      int c;
263                      int totalW = 0;
264
265                      while(columnStart && columnStart.rowSpan)
266                         columnStart = columnStart.next;
267
268                      for(c = 0, column = columnStart; c<cell.span && column; c++)
269                      {
270                         column.rowSpan = cell.rowSpan;
271                         if(cell.span == 1)
272                            totalW += column.w;
273                         column = column.next;
274                      }
275                      if(cell.span == 1 && totalW < cell.lineW)
276                      {
277                         for(c = 0, column = columnStart; c<cell.span && column; c++, column = column.next)
278                         {
279                            int desire = cell.lineW - totalW;
280                            column.desire += desire / cell.span;
281                         }
282                         needed += cell.lineW - totalW;
283                      }
284
285                      columnStart = column;
286                   }
287                   for(column = table.columns.first; column; column = column.next)
288                      if(column.rowSpan) column.rowSpan--;
289                   row = NextBlockUp(surface, row, null, 0);
290                }
291                else
292                   row = NextBlock(surface, row, null, 0);
293             }
294
295             // Take care of spanning across columns (minw)
296             for(column = table.columns.first; column; column = column.next)
297                column.rowSpan = 0;
298
299             for(row = table.subBlocks.first; row && row.type != TABLE; )
300             {
301                if(row.type == TR)
302                {
303                   Block cell;
304                   Column columnStart = table.columns.first;
305
306                   for(cell = row.subBlocks.first; cell; cell = cell.next)
307                   {
308                      int c;
309                      int totalW = 0;
310                      int sumDesires = 0;
311
312                      while(columnStart && columnStart.rowSpan)
313                         columnStart = columnStart.next;
314
315                      for(c = 0, column = columnStart; c<cell.span && column; c++)
316                      {
317                         column.rowSpan = cell.rowSpan;
318                         totalW += column.w;
319                         sumDesires += column.desire;
320                         column = column.next;
321                      }
322                      if(cell.span > 1 && totalW < cell.minW)
323                      {
324                         for(c = 0, column = columnStart; c<cell.span && column; c++)
325                         {
326                            if(column.desire)
327                            {
328                               int given = (column.desire) * (cell.minW - totalW) / sumDesires;
329                               column.minW += given;
330                            }
331                            column = column.next;
332                         }
333
334                         // Check if we've got enough now...
335                         totalW = 0;
336                         for(c = 0, column = columnStart; c<cell.span && column; c++)
337                         {
338                            totalW += column.minW;
339                            column = column.next;
340                         }
341
342                         if(totalW < cell.minW)
343                         {
344                            for(c = 0, column = columnStart; c<cell.span && column; c++)
345                            {
346                               column.minW = Max(column.minW, (cell.minW - totalW) / cell.span);
347                               column = column.next;
348                            }
349                         }
350                      }
351                      columnStart = column;
352                   }
353                   for(column = table.columns.first; column; column = column.next)
354                      if(column.rowSpan) column.rowSpan--;
355                   row = NextBlockUp(surface, row, null, 0);
356                }
357                else
358                   row = NextBlock(surface, row, null, 0);
359             }
360
361             for(column = table.columns.first; column; column = column.next)
362             {
363                if(column.minW > column.w)
364                {
365                   w += column.minW - column.w;
366                   column.w = column.minW;
367                }
368             }
369
370
371             // Repeat Step 1: Weights how to distribute
372             needed = 0;
373             for(column = table.columns.first; column; column = column.next)
374             {
375                column.rowSpan = 0;
376                column.desire = 0;
377             }
378             for(row = table.subBlocks.first; row && row.type != TABLE; )
379             {
380                if(row.type == TR)
381                {
382                   Block cell;
383                   Column columnStart = table.columns.first;
384
385                   for(cell = row.subBlocks.first; cell; cell = cell.next)
386                   {
387                      int c;
388                      int totalW = 0;
389
390                      while(columnStart && columnStart.rowSpan)
391                         columnStart = columnStart.next;
392
393                      for(c = 0, column = columnStart; c<cell.span && column; c++)
394                      {
395                         column.rowSpan = cell.rowSpan;
396                         if(/*cell.span == 1 && */cell.width)
397                            totalW += column.w;
398                         column = column.next;
399                      }
400                      if(/*cell.span == 1 && */totalW < cell.lineW && cell.width)
401                      {
402                         for(c = 0, column = columnStart; c<cell.span && column; c++, column = column.next)
403                         {
404                            int desire = cell.lineW - totalW;
405                            column.desire += desire / cell.span;
406                         }
407                         needed += cell.lineW - totalW;
408                      }
409
410                      columnStart = column;
411                   }
412                   for(column = table.columns.first; column; column = column.next)
413                      if(column.rowSpan) column.rowSpan--;
414                      row = NextBlockUp(surface, row, null, 0);
415                }
416                else
417                   row = NextBlock(surface, row, null, 0);
418             }
419
420             // Step 2: Do the distribution
421             if(needed)
422             {
423                for(column = table.columns.first; column; column = column.next)
424                {
425                   if(column.width)
426                   {
427                      int give = (column.desire) * (table.w - w) / needed;
428                      give = Min(give, column.width - column.w);
429                      if(give > 0)
430                         column.w += give;
431                   }
432                }
433             }
434             w = 0;
435             for(column = table.columns.first; column; column = column.next)
436                w += column.w;
437          }
438
439          if(w<table.w)
440          {
441             // Repease Step 1: Weights how to distribute
442             int needed = 0;
443             for(column = table.columns.first; column; column = column.next)
444             {
445                column.rowSpan = 0;
446                column.desire = 0;
447             }
448             for(row = table.subBlocks.first; row && row.type != TABLE; )
449             {
450                if(row.type == TR)
451                {
452                   Block cell;
453                   Column columnStart = table.columns.first;
454
455                   for(cell = row.subBlocks.first; cell; cell = cell.next)
456                   {
457                      int c;
458                      int totalW = 0;
459
460                      while(columnStart && columnStart.rowSpan)
461                         columnStart = columnStart.next;
462
463                      for(c = 0, column = columnStart; c<cell.span && column; c++)
464                      {
465                         column.rowSpan = cell.rowSpan;
466                         if(/*cell.span == 1 && */!cell.width)
467                            totalW += column.w;
468                         column = column.next;
469                      }
470                      if(/*cell.span == 1 && */totalW < cell.lineW && !cell.width)
471                      {
472                         for(c = 0, column = columnStart; c<cell.span && column; c++, column = column.next)
473                         {
474                            int desire = cell.lineW - totalW;
475                            column.desire += desire / cell.span;
476                         }
477                         needed += cell.lineW - totalW;
478                      }
479
480                      columnStart = column;
481                   }
482                   for(column = table.columns.first; column; column = column.next)
483                      if(column.rowSpan) column.rowSpan--;
484                   row = NextBlockUp(surface, row, null, 0);
485                }
486                else
487                   row = NextBlock(surface, row, null, 0);
488             }
489
490             // Step 2: Do the distribution
491             if(needed)
492             {
493                for(column = table.columns.first; column; column = column.next)
494                {
495                   if(!column.width)
496                   {
497                      int give = (column.desire) * (table.w - w) / needed;
498                      column.w += give;
499                   }
500                }
501             }
502
503             w = 0;
504             for(column = table.columns.first; column; column = column.next)
505                w += column.w;
506          }
507
508          // Repartition the rest of the space in the columns
509          if(w < table.w)
510          {
511             int numNotFixed = 0;
512             int totalLineW = 0;
513             for(column = table.columns.first; column; column = column.next)
514             {
515                if(!column.width)
516                {
517                   numNotFixed++;
518                   totalLineW += column.lineW;
519                }
520             }
521             if(numNotFixed)
522             {
523                for(column = table.columns.first; column; column = column.next)
524                {
525                   if(!column.width)
526                   {
527                      int give;
528                      if(totalLineW)
529                         give = (table.w - w) * column.lineW / totalLineW;
530                      else
531                         give = (table.w - w) / numNotFixed;
532                      column.w += give;
533                   }
534                }
535             }
536             else
537             {
538                for(column = table.columns.first; column; column = column.next)
539                   totalLineW += column.lineW;
540                for(column = table.columns.first; column; column = column.next)
541                {
542                   int give;
543                   if(totalLineW)
544                      give = (table.w - w) * column.lineW / totalLineW;
545                   else
546                      give = (table.w - w) / table.columns.count;
547                   column.w += give;
548                }
549             }
550             w = 0;
551             for(column = table.columns.first; column; column = column.next)
552                w += column.w;
553          }
554
555
556          {
557             /*switch(table.halign)
558             {
559                case middle:
560                   startX = Max(left, (left + right - table.w)/2);
561                   break;
562                case HorizontalAlignment::right:
563                   startX = Max(left, right - table.w);
564                   break;
565             }*/
566          }
567
568          // Pass 2: Figure out heights
569          h = 0;
570          for(column = table.columns.first; column; column = column.next)
571             column.rowSpan = 0;
572          for(row = table.subBlocks.first; row && row.type != TABLE; )
573          {
574             if(row.type == TR)
575             {
576                Block cell;
577                OldList leftObjects { };
578                OldList rightObjects { };
579
580                row.height = 0;
581
582                column = table.columns.first;
583                row.h = 0;
584
585                sx = startX;
586                for(cell = row.subBlocks.first; cell; cell = cell.next)
587                {
588                   if(cell.type == TD)
589                   {
590                      int centered = 0;
591                      Block block;
592                      int textPos = 0;
593                      int c;
594                      int cellMaxH = row.h;
595                      int lineH = 0;
596                      int y = 0;
597                      AlignedObject object, nextObject;
598
599                      // Disconnect the cell
600                      Block parent = cell.parent;
601                      Block next = cell.next;
602                      cell.parent = null;
603                      cell.next = null;
604
605                      if(column)
606                      {
607                         if(column.rowSpan)
608                            column = column.next;
609                         // TOCHECK: Added column null check here..
610                         if(column && cell.rowSpan)
611                            column.rowSpan = cell.rowSpan;
612                      }
613
614                      cell.w = 0;
615                      for(c = 0; (!cell.span || c<cell.span) && column; c++)
616                      {
617                         cell.w += column.w;
618                         column = column.next;
619                      }
620
621                      cell.h = 0;
622
623                      block = cell.subBlocks.first;
624                      for(;block;)
625                      {
626                         int newLineH, lineW;
627                         Block nextCellBlock;
628                         int nextCellPos;
629                         bool changeLine;
630                         int cellW = cell.w;
631
632                         for(object = leftObjects.last; object; object = nextObject)
633                         {
634                            nextObject = object.prev;
635                            if(y < object.untilY || object.next)
636                               cellW -= object.w;
637                            else
638                               leftObjects.Delete(object);
639                         }
640                         for(object = rightObjects.last; object; object = nextObject)
641                         {
642                            nextObject = object.prev;
643                            if(y < object.untilY || object.next)
644                               cellW -= object.w;
645                            else
646                               rightObjects.Delete(object);
647                         }
648                         cellW = Max(cellW, 0);
649
650                         // TRIED ADDING THIS CODE HERE...
651                         {
652                            int x;
653                            int left, right;
654                            // Compute aligned objects
655                            left = sx + table.cellPadding; // Add cell border/margins here?
656                            right = sx + cellW - table.cellPadding; // Subtract cell border/margins here?
657
658                            for(object = leftObjects.last; object; object = nextObject)
659                            {
660                               nextObject = object.prev;
661                               if(y < object.untilY || object.next)
662                                  left += object.w;
663                               else
664                                  leftObjects.Delete(object);
665                            }
666                            for(object = rightObjects.last; object; object = nextObject)
667                            {
668                               nextObject = object.prev;
669                               if(y < object.untilY || object.next)
670                                  right -= object.w;
671                               else
672                                  rightObjects.Delete(object);
673                            }
674                            right = Max(left, right);
675
676                            if(cell.halign == middle /*|| thisLineCentered*/)
677                            {
678                               x = (left + right - lineW)/2;
679                               x = Max(x, left);
680                            }
681                            else if(cell.halign == HorizontalAlignment::right)
682                            {
683                               x = right - lineW;
684                               x = Max(x, left);
685                            }
686                            else
687                               x = left;
688
689                            newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, right - left /*cellW*/, cellMaxH, flags, y, &leftObjects, &rightObjects, &changeLine, true, sy, x);
690                         }
691                         textPos = nextCellPos;
692                         block = nextCellBlock;
693
694                         lineH = Max(lineH, newLineH);
695                         if(changeLine)
696                         {
697                            //cell.h += lineH;
698                            //cellMaxH -= lineH;
699
700                            cell.h += newLineH;
701                            y += newLineH;
702                            cellMaxH -= newLineH;
703                            //lineH = 0;
704                         }
705                      }
706
707                      for(object = leftObjects.last; object; object = nextObject)
708                      {
709                         nextObject = object.prev;
710                         y = Max(y, object.untilY);
711                         leftObjects.Delete(object);
712                      }
713                      for(object = rightObjects.last; object; object = nextObject)
714                      {
715                         nextObject = object.prev;
716                         y = Max(y, object.untilY);
717                         rightObjects.Delete(object);
718                      }
719                      sx += cell.w;
720                      cell.h = y;
721
722                      //cell.h += lineH;
723                      //cellMaxH -= lineH;
724
725                      cell.parent = parent;
726                      cell.next = next;
727
728                      row.height = Max(row.height, cell.height);
729
730                      cell.h = Max(cell.h, cell.height);
731
732                      row.h = Max(row.h, cell.h);
733                   }
734                }
735                // row.h = Max(row.h, row.height);
736                h += row.h;
737                sy += row.h;
738
739                for(column = table.columns.first; column; column = column.next)
740                {
741                   if(column.rowSpan)
742                      column.rowSpan--;
743                }
744                row = NextBlockUp(surface, row, null, 0);
745             }
746             else
747                row = NextBlock(surface, row, null, 0);
748          }
749
750          if(table.pHeight)
751             table.h = maxH * table.pHeight / 100;
752          else if(table.height)
753             table.h = table.height;
754          else
755             table.h = 0;
756
757          if(h > table.h)
758          {
759             table.h = h;
760          }
761
762          if(table.h > h)
763          {
764             int numNotFixed = 0;
765             // Repartition the rest of the space in the rows
766             for(row = table.subBlocks.first; row && row.type != TABLE; )
767             {
768                if(row.type == TR)
769                {
770                   if(!row.height)
771                      numNotFixed++;
772                   row = NextBlockUp(surface, row, null, 0);
773                }
774                else
775                   row = NextBlock(surface, row, null, 0);
776             }
777             if(numNotFixed)
778             {
779                for(row = table.subBlocks.first; row && row.type != TABLE; )
780                {
781                   if(row.type == TR)
782                   {
783                      row.h += (table.h - h) / numNotFixed;
784                      row = NextBlockUp(surface, row, null, 0);
785                   }
786                   else
787                      row = NextBlock(surface, row, null, 0);
788                }
789             }
790          }
791       }
792    }
793
794    *height = table.h;
795    *width = table.w;
796 }
797
798 static void RenderCell(HTMLView browser, Surface surface, Block cell, int cellX, int y)
799 {
800    int centered = 0;
801    Block block = cell;
802    int textPos = 0;
803    Block row = cell.parent;
804    int x;
805    int maxH = row.h;
806    int cellW = cell.w;
807    int lineH = 0;
808    AlignedObject object, nextObject;
809    OldList leftObjects { };
810    OldList rightObjects { };
811    Block table;
812
813    // Disconnect the cell
814    Block parent = cell.parent;
815    Block next = cell.next;
816    table = cell;
817    while(table && table.type != TABLE) table = table.parent;
818
819    cell.parent = null;
820    cell.next = null;
821
822    /*
823    if(cell.width)
824       cellW = cell.width;
825    */
826
827    if(cell.bitmap)
828    {
829       ColorAlpha fg = surface.GetForeground();
830       surface.SetForeground(white);
831
832       // surface.Stretch(cell.bitmap, x,y,0,0,cell.w,cell.h,cell.bitmap.width, cell.bitmap.height);
833       surface.Tile(cell.bitmap, cellX,y,cellW,row.h);
834
835       surface.SetForeground(fg);
836    }
837    else if(cell.bgColor)
838    {
839       surface.SetBackground(cell.bgColor);
840       surface.Area(cellX, y, cellX+cellW-1, y+row.h-1);
841    }
842
843    //surface.SetForeground(Color { 85,85,255 });
844    //surface.Rectangle(cellX, y, cellX+cellW-1, y+row.h-1);
845
846    if(cell.valign == middle)
847    {
848       y += (row.h - cell.h) / 2;
849    }
850    else if(cell.valign == bottom)
851    {
852       y += row.h - cell.h;
853    }
854    browser.isSelected = false;
855
856    // Render whole cell
857    while(block && table)
858    {
859       int lineW, newLineH;
860       Block nextCellBlock;
861       int nextCellPos;
862       int thisLineCentered = centered;
863       int left, right;
864       int maxW;
865       bool changeLine;
866       Font font;
867
868       // Compute aligned objects
869       left = cellX + table.cellPadding; // Add cell border/margins here?
870       right = cellX + cellW - table.cellPadding; // Subtract cell border/margins here?
871
872       for(object = leftObjects.last; object; object = nextObject)
873       {
874          nextObject = object.prev;
875          if(y < object.untilY || object.next)
876             left += object.w;
877          else
878             leftObjects.Delete(object);
879       }
880       for(object = rightObjects.last; object; object = nextObject)
881       {
882          nextObject = object.prev;
883          if(y < object.untilY || object.next)
884             right -= object.w;
885          else
886             rightObjects.Delete(object);
887       }
888       right = Max(left, right);
889       maxW = right - left;
890
891       font = surface.font;
892       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
893       surface.font = font;
894
895       if(cell.halign == middle || thisLineCentered)
896       {
897          x = (left + right - lineW)/2;
898          x = Max(x, left);
899       }
900       else if(cell.halign == HorizontalAlignment::right)
901       {
902          x = right - lineW;
903          x = Max(x, left);
904       }
905       else
906          x = left;
907
908       lineH = Max(lineH, newLineH);
909
910       RenderLine(browser, surface, x, y, cellW, newLineH, block, textPos, nextCellBlock, nextCellPos, left, right);
911
912       if(changeLine)
913       {
914          //y += lineH;
915          //maxH -= lineH;
916          y += newLineH;
917          maxH -= newLineH;
918          //lineH = 0;
919       }
920       textPos = nextCellPos;
921       block = nextCellBlock;
922    }
923    //y += lineH;
924    //maxH -= lineH;
925    for(object = leftObjects.last; object; object = nextObject)
926    {
927       nextObject = object.prev;
928       y = Max(y, object.untilY);
929       leftObjects.Delete(object);
930    }
931    for(object = rightObjects.last; object; object = nextObject)
932    {
933       nextObject = object.prev;
934       y = Max(y, object.untilY);
935       rightObjects.Delete(object);
936    }
937
938    cell.parent = parent;
939    cell.next = next;
940 }
941
942
943 static void RenderRow(HTMLView browser, Surface surface, Block row, Block table, int x, int y)
944 {
945    Block cell;
946    int c = 0;
947    Column column = table.columns.first;
948    for(cell = row.subBlocks.first; cell; cell = cell.next)
949    {
950       if(cell.type == TD)
951       {
952          int c;
953
954          while(column && column.rowSpan)
955             column = column.next;
956
957          RenderCell(browser, surface, cell, x, y);
958
959          for(c = 0; c<cell.span && column; c++)
960          {
961             column.rowSpan = cell.rowSpan;
962             x += column.w;
963             column = column.next;
964          }
965       }
966       c++;
967    }
968 }
969
970 void RenderTable(HTMLView browser, Surface surface, int x, int y, int w, int h, int left, int right, Block table)
971 {
972    Block row;
973    Column column;
974
975    switch(table.halign)
976    {
977       case middle:
978          x = Max(left, (left + right - table.w)/2);
979          break;
980       case HorizontalAlignment::right:
981          x = Max(left, right - table.w);
982          break;
983    }
984
985    if(table.bitmap)
986    {
987       ColorAlpha fg = surface.GetForeground();
988       surface.SetForeground(white);
989
990       // surface.Stretch(table.bitmap, x,y,0,0,table.w,table.h,table.bitmap.width, table.bitmap.height);
991       surface.Tile(table.bitmap, x,y,table.w,table.h);
992
993       surface.SetForeground(fg);
994    }
995    else if(table.bgColor)
996    {
997       surface.SetBackground(table.bgColor);
998       surface.Area(x,y,x+table.w-1,y+table.h-1);
999    }
1000
1001    for(column = table.columns.first; column; column = column.next)
1002       column.rowSpan = 0;
1003
1004    for(row = table.subBlocks.first; row && row.type != TABLE; )
1005    {
1006       if(row.type == TR)
1007       {
1008          RenderRow(browser, surface, row, table, x, y);
1009          y += row.h;
1010          for(column = table.columns.first; column; column = column.next)
1011          {
1012             if(column.rowSpan)
1013                column.rowSpan--;
1014          }
1015          row = NextBlockUp(surface, row, null, 0);
1016       }
1017       else
1018          row = NextBlock(surface, row, null, 0);
1019    }
1020 }
1021
1022
1023 static bool PickCell(HTMLView browser, Surface surface, Block cell, int cellX, int y,
1024                      int pickX, int pickY, Block* pickBlock, int * pickTextPos)
1025 {
1026    bool result = false;
1027    int centered = 0;
1028    Block block = cell;
1029    int textPos = 0;
1030    Block row = cell.parent;
1031    int x;
1032    int maxH = row.h;
1033    int cellW = cell.w;
1034    int lineH = 0;
1035    AlignedObject object, nextObject;
1036    OldList leftObjects { };
1037    OldList rightObjects { };
1038
1039    // Disconnect the cell
1040    Block parent = cell.parent;
1041    Block next = cell.next;
1042    Block table = cell;
1043
1044    while(table && table.type != TABLE) table = table.parent;
1045
1046    cell.parent = null;
1047    cell.next = null;
1048
1049    if(cell.valign == middle)
1050    {
1051       y += (row.h - cell.h) / 2;
1052    }
1053    else if(cell.valign == bottom)
1054    {
1055       y += row.h - cell.h;
1056    }
1057
1058    // Render whole cell
1059    for(;block && table && !result;)
1060    {
1061       int lineW, newLineH;
1062       Block nextCellBlock;
1063       int nextCellPos;
1064       int thisLineCentered = centered;
1065       int left, right;
1066       int maxW;
1067       bool changeLine;
1068
1069       Font font;
1070
1071       // Compute aligned objects
1072       left = cellX + table.cellPadding; // Add cell border/margins here?
1073       right = cellX + cellW - table.cellPadding; // Subtract cell border/margins here?
1074
1075       for(object = leftObjects.last; object; object = nextObject)
1076       {
1077          nextObject = object.prev;
1078          if(y < object.untilY || object.next)
1079             left += object.w;
1080          else
1081             leftObjects.Delete(object);
1082       }
1083       for(object = rightObjects.last; object; object = nextObject)
1084       {
1085          nextObject = object.prev;
1086          if(y < object.untilY || object.next)
1087             right -= object.w;
1088          else
1089             rightObjects.Delete(object);
1090       }
1091       right = Max(left, right);
1092       maxW = right - left;
1093
1094       font = surface.font;
1095       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1096       surface.font = font;
1097
1098       //surface.TextFont(font);
1099
1100       if(cell.halign == middle || thisLineCentered)
1101       {
1102          x = (left + right - lineW)/2;
1103          x = Max(x, left);
1104       }
1105       else if(cell.halign == HorizontalAlignment::right)
1106       {
1107          x = right - lineW;
1108          x = Max(x, left);
1109       }
1110       else
1111          x = left;
1112
1113       lineH = Max(lineH, newLineH);
1114
1115       result = PickLine(browser, surface, x, y, cellW, newLineH, block, textPos, nextCellBlock, nextCellPos, left, right, pickX, pickY, pickBlock, pickTextPos);
1116
1117       if(changeLine)
1118       {
1119          //y += lineH;
1120          //maxH -= lineH;
1121          y += newLineH;
1122          maxH -= newLineH;
1123          //lineH = 0;
1124       }
1125       textPos = nextCellPos;
1126       block = nextCellBlock;
1127    }
1128    //y += lineH;
1129    //maxH -= lineH;
1130    for(object = leftObjects.last; object; object = nextObject)
1131    {
1132       nextObject = object.prev;
1133       y = Max(y, object.untilY);
1134       leftObjects.Delete(object);
1135    }
1136    for(object = rightObjects.last; object; object = nextObject)
1137    {
1138       nextObject = object.prev;
1139       y = Max(y, object.untilY);
1140       rightObjects.Delete(object);
1141    }
1142
1143    cell.parent = parent;
1144    cell.next = next;
1145    return result;
1146 }
1147
1148
1149 static bool PickRow(HTMLView browser, Surface surface, Block row, Block table, int x, int y,
1150                     int pickX, int pickY, Block* pickBlock, int * pickTextPos)
1151 {
1152    bool result = false;
1153    Block cell;
1154    int c = 0;
1155    Column column = table.columns.first;
1156    for(cell = row.subBlocks.first; cell; cell = cell.next)
1157    {
1158       if(cell.type == TD)
1159       {
1160          int c;
1161
1162          while(column && column.rowSpan)
1163             column = column.next;
1164
1165          result = PickCell(browser, surface, cell, x, y, pickX, pickY, pickBlock, pickTextPos);
1166          if(result)
1167             break;
1168
1169          for(c = 0; c<cell.span && column; c++)
1170          {
1171             column.rowSpan = cell.rowSpan;
1172             x += column.w;
1173             column = column.next;
1174          }
1175       }
1176       c++;
1177    }
1178    return result;
1179 }
1180
1181 bool PickTable(HTMLView browser, Surface surface, int x, int y, int w, int h, int left, int right, Block table,
1182                int pickX, int pickY, Block* pickBlock, int * pickTextPos)
1183 {
1184    bool result = false;
1185    Block row;
1186    Column column;
1187
1188    switch(table.halign)
1189    {
1190       case middle:
1191          x = Max(left, (left + right - table.w)/2);
1192          break;
1193       case HorizontalAlignment::right:
1194          x = Max(left, right - table.w);
1195          break;
1196    }
1197
1198    for(column = table.columns.first; column; column = column.next)
1199       column.rowSpan = 0;
1200
1201    for(row = table.subBlocks.first; row && row.type != TABLE; )
1202    {
1203       if(row.type == TR)
1204       {
1205          result = PickRow(browser, surface, row, table, x, y, pickX, pickY, pickBlock, pickTextPos);
1206          y += row.h;
1207          for(column = table.columns.first; column; column = column.next)
1208          {
1209             if(column.rowSpan)
1210                column.rowSpan--;
1211          }
1212          if(result)
1213             break;
1214          row = NextBlockUp(surface, row, null, 0);
1215       }
1216       else
1217          row = NextBlock(surface, row, null, 0);
1218    }
1219    return result;
1220 }
1221
1222 static void PositionCell(HTMLView browser, Surface surface, Block cell, int cellX, int y)
1223 {
1224    int centered = 0;
1225    Block block = cell;
1226    int textPos = 0;
1227    Block row = cell.parent;
1228    int x;
1229    int maxH = row.h;
1230    int cellW = cell.w;
1231    int lineH = 0;
1232    AlignedObject object, nextObject;
1233    OldList leftObjects { };
1234    OldList rightObjects { };
1235
1236    // Disconnect the cell
1237    Block parent = cell.parent;
1238    Block next = cell.next;
1239    Block table;
1240
1241    table = cell;
1242    while(table && table.type != TABLE) table = table.parent;
1243    cell.parent = null;
1244    cell.next = null;
1245
1246    if(cell.valign == middle)
1247    {
1248       y += (row.h - cell.h) / 2;
1249    }
1250    else if(cell.valign == bottom)
1251    {
1252       y += row.h - cell.h;
1253    }
1254
1255    // Render whole cell
1256    for(;block && table;)
1257    {
1258       int lineW, newLineH;
1259       Block nextCellBlock;
1260       int nextCellPos;
1261       int thisLineCentered = centered;
1262       int left, right;
1263       int maxW;
1264       bool changeLine;
1265
1266       Font font;
1267
1268       // Compute aligned objects
1269       left = cellX + table.cellPadding; // Add cell border/margins here?
1270       right = cellX + cellW - table.cellPadding; // Subtract cell border/margins here?
1271
1272       for(object = leftObjects.last; object; object = nextObject)
1273       {
1274          nextObject = object.prev;
1275          if(y < object.untilY || object.next)
1276             left += object.w;
1277          else
1278             leftObjects.Delete(object);
1279       }
1280       for(object = rightObjects.last; object; object = nextObject)
1281       {
1282          nextObject = object.prev;
1283          if(y < object.untilY || object.next)
1284             right -= object.w;
1285          else
1286             rightObjects.Delete(object);
1287       }
1288       right = Max(left, right);
1289       maxW = right - left;
1290
1291       font = surface.font;
1292       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1293       surface.font = font;
1294
1295       // surface.TextFont(font);
1296
1297       if(cell.halign == middle || thisLineCentered)
1298       {
1299          x = (left + right - lineW)/2;
1300          x = Max(x, left);
1301       }
1302       else if(cell.halign == HorizontalAlignment::right)
1303       {
1304          x = right - lineW;
1305          x = Max(x, left);
1306       }
1307       else
1308          x = left;
1309
1310       lineH = Max(lineH, newLineH);
1311
1312       PositionLine(browser, surface, x, y, cellW, newLineH, block, textPos, nextCellBlock, nextCellPos, left, right);
1313
1314       if(changeLine)
1315       {
1316          //y += lineH;
1317          //maxH -= lineH;
1318          y += newLineH;
1319          maxH -= newLineH;
1320          //lineH = 0;
1321       }
1322       textPos = nextCellPos;
1323       block = nextCellBlock;
1324    }
1325    //y += lineH;
1326    //maxH -= lineH;
1327    for(object = leftObjects.last; object; object = nextObject)
1328    {
1329       nextObject = object.prev;
1330       y = Max(y, object.untilY);
1331       leftObjects.Delete(object);
1332    }
1333    for(object = rightObjects.last; object; object = nextObject)
1334    {
1335       nextObject = object.prev;
1336       y = Max(y, object.untilY);
1337       rightObjects.Delete(object);
1338    }
1339
1340    cell.parent = parent;
1341    cell.next = next;
1342 }
1343
1344
1345 static void PositionRow(HTMLView browser, Surface surface, Block row, Block table, int x, int y)
1346 {
1347    Block cell;
1348    int c = 0;
1349    Column column = table.columns.first;
1350    for(cell = row.subBlocks.first; cell; cell = cell.next)
1351    {
1352       if(cell.type == TD)
1353       {
1354          int c;
1355
1356          while(column && column.rowSpan)
1357             column = column.next;
1358
1359          PositionCell(browser, surface, cell, x, y);
1360
1361          for(c = 0; c<cell.span && column; c++)
1362          {
1363             column.rowSpan = cell.rowSpan;
1364             x += column.w;
1365             column = column.next;
1366          }
1367       }
1368       c++;
1369    }
1370 }
1371
1372 void PositionTable(HTMLView browser, Surface surface, int x, int y, int w, int h, int left, int right, Block table)
1373 {
1374    Block row;
1375    Column column;
1376
1377    switch(table.halign)
1378    {
1379       case middle:
1380          x = Max(left, (left + right - table.w)/2);
1381          break;
1382       case HorizontalAlignment::right:
1383          x = Max(left, right - table.w);
1384          break;
1385    }
1386
1387    for(column = table.columns.first; column; column = column.next)
1388       column.rowSpan = 0;
1389
1390    for(row = table.subBlocks.first; row && row.type != TABLE; )
1391    {
1392       if(row.type == TR)
1393       {
1394          PositionRow(browser, surface, row, table, x, y);
1395          y += row.h;
1396          for(column = table.columns.first; column; column = column.next)
1397          {
1398             if(column.rowSpan)
1399                column.rowSpan--;
1400          }
1401          row = NextBlockUp(surface, row, null, 0);
1402       }
1403       else
1404          row = NextBlock(surface, row, null, 0);
1405    }
1406 }
1407