import "HTMLView"
class Column : struct
{
Column prev, next;
int w; // Actual width for current rendering
int minW, lineW;
int rowSpan;
int width;
int desire;
};
void ComputeTable(Surface surface, Block table, int textPos, int * width, int * height, int maxW, int maxH, RenderFlags flags, int sy, int sx)
{
if(flags.minW || flags.lineW || flags.width)
{
Block row;
Column column;
int w = 0, h = 0;
int startX = sx;
// Pass 1: Figure out column widths
for(column = table.columns.first; column; column = column.next)
{
column.w = 0;
if(flags.minW)
{
column.minW = 0;
column.width = 0;
}
if(flags.lineW)
{
column.lineW = 0;
}
// Temporary variable:
column.rowSpan = 0;
}
for(row = table.subBlocks.first; row && row.type != TABLE; )
{
if(row.type == TR)
{
Block cell;
column = table.columns.first;
for(cell = row.subBlocks.first; cell; cell = cell.next)
{
if(cell.type == TD)
{
int c;
int centered = 0;
int minW = 0, lineW = 0;
Block block;
int textPos = 0;
// Disconnect the cell
Block parent = cell.parent;
Block next = cell.next;
cell.parent = null;
cell.next = null;
while(column && column.rowSpan)
column = column.next;
if(!column)
{
column = Column { rowSpan = cell.rowSpan };
// if(cell.rowSpan) Do proper thing if 0 rowSpan
table.columns.Add(column);
}
// Process whole cell
block = cell.subBlocks.first;
for(;block;)
{
int w;
Block nextCellBlock;
int nextCellPos;
// Minimum width for this column
if(flags.minW)
{
if(cell.noWrap)
{
ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, ¢ered, &w, MAXINT, 0, RenderFlags { lineW = true }, 0, null, null, null, true, sy, sx);
/*if(cell.pWidth)
w = Max(maxW * cell.pWidth / 100, w);*/
}
else
ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, ¢ered, &w, 0, 0, flags, 0, null, null, null, true, sy, sx);
// Width specified absolute is minimum width
/*
if(cell.width)
w = Max(cell.width, w);
*/
minW = Max(minW, w);
}
if(flags.lineW)
{
// Width specified absolute will not extend
if(maxW < cell.minW || cell.width)
{
//lineW = cell.minW;
lineW = Max(cell.minW, cell.width);
break;
}
else
{
ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, ¢ered, &w, maxW, 0, RenderFlags { lineW = true }, 0, null, null, null, true, sy, sx);
if(cell.pWidth)
w = Max(maxW * cell.pWidth / 100, w);
lineW = Max(lineW, w);
}
}
textPos = nextCellPos;
block = nextCellBlock;
}
cell.parent = parent;
cell.next = next;
minW += table.cellPadding * 2;
lineW += table.cellPadding * 2;
if(flags.minW)
cell.minW = minW;
if(flags.lineW)
cell.lineW = lineW;
// First only process non spanning cells
if(cell.span == 1)
{
if(flags.minW)
{
column.width = Max(column.width, cell.width);
column.minW = Max(column.minW, cell.minW);
}
if(flags.lineW)
{
column.lineW = Max(column.lineW, cell.lineW);
column.minW = Max(column.minW, cell.minW);
}
}
for(c = 0; c table.w)
table.w = w;
//if(flags.width)
{
if(flags.lineW /*&& flags.width*/)
{
// Expand using lineW
if(!table.pWidth && !table.width)
{
int totalLineW = 0;
for(column = table.columns.first; column; column = column.next)
column.rowSpan = 0;
for(row = table.subBlocks.first; row && row.type != TABLE; )
{
if(row.type == TR)
{
Block cell;
int rowLineW = 0;
column = table.columns.first;
for(cell = row.subBlocks.first; cell; cell = cell.next)
{
int c;
int sumColW = 0;
while(column && column.rowSpan)
column = column.next;
for(c = 0; c 1 && totalW < cell.minW)
{
for(c = 0, column = columnStart; c column.w)
{
w += column.minW - column.w;
column.w = column.minW;
}
}
// Repeat Step 1: Weights how to distribute
needed = 0;
for(column = table.columns.first; column; column = column.next)
{
column.rowSpan = 0;
column.desire = 0;
}
for(row = table.subBlocks.first; row && row.type != TABLE; )
{
if(row.type == TR)
{
Block cell;
Column columnStart = table.columns.first;
for(cell = row.subBlocks.first; cell; cell = cell.next)
{
int c;
int totalW = 0;
while(columnStart && columnStart.rowSpan)
columnStart = columnStart.next;
for(c = 0, column = columnStart; c 0)
column.w += give;
}
}
}
w = 0;
for(column = table.columns.first; column; column = column.next)
w += column.w;
}
if(w table.h)
{
table.h = h;
}
if(table.h > h)
{
int numNotFixed = 0;
// Repartition the rest of the space in the rows
for(row = table.subBlocks.first; row && row.type != TABLE; )
{
if(row.type == TR)
{
if(!row.height)
numNotFixed++;
row = NextBlockUp(surface, row, null, 0);
}
else
row = NextBlock(surface, row, null, 0);
}
if(numNotFixed)
{
for(row = table.subBlocks.first; row && row.type != TABLE; )
{
if(row.type == TR)
{
row.h += (table.h - h) / numNotFixed;
row = NextBlockUp(surface, row, null, 0);
}
else
row = NextBlock(surface, row, null, 0);
}
}
}
}
}
*height = table.h;
*width = table.w;
}
static void RenderCell(HTMLView browser, Surface surface, Block cell, int cellX, int y)
{
int centered = 0;
Block block = cell;
int textPos = 0;
Block row = cell.parent;
int x;
int maxH = row.h;
int cellW = cell.w;
int lineH = 0;
AlignedObject object, nextObject;
OldList leftObjects { };
OldList rightObjects { };
Block table;
// Disconnect the cell
Block parent = cell.parent;
Block next = cell.next;
table = cell;
while(table && table.type != TABLE) table = table.parent;
cell.parent = null;
cell.next = null;
/*
if(cell.width)
cellW = cell.width;
*/
if(cell.bitmap)
{
ColorAlpha fg = surface.GetForeground();
surface.SetForeground(white);
// surface.Stretch(cell.bitmap, x,y,0,0,cell.w,cell.h,cell.bitmap.width, cell.bitmap.height);
surface.Tile(cell.bitmap, cellX,y,cellW,row.h);
surface.SetForeground(fg);
}
else if(cell.bgColor)
{
surface.SetBackground(cell.bgColor);
surface.Area(cellX, y, cellX+cellW-1, y+row.h-1);
}
//surface.SetForeground(Color { 85,85,255 });
//surface.Rectangle(cellX, y, cellX+cellW-1, y+row.h-1);
if(cell.valign == middle)
{
y += (row.h - cell.h) / 2;
}
else if(cell.valign == bottom)
{
y += row.h - cell.h;
}
browser.isSelected = false;
// Render whole cell
while(block && table)
{
int lineW, newLineH;
Block nextCellBlock;
int nextCellPos;
int thisLineCentered = centered;
int left, right;
int maxW;
bool changeLine;
Font font;
// Compute aligned objects
left = cellX + table.cellPadding; // Add cell border/margins here?
right = cellX + cellW - table.cellPadding; // Subtract cell border/margins here?
for(object = leftObjects.last; object; object = nextObject)
{
nextObject = object.prev;
if(y < object.untilY || object.next)
left += object.w;
else
leftObjects.Delete(object);
}
for(object = rightObjects.last; object; object = nextObject)
{
nextObject = object.prev;
if(y < object.untilY || object.next)
right -= object.w;
else
rightObjects.Delete(object);
}
right = Max(left, right);
maxW = right - left;
font = surface.font;
newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, ¢ered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
surface.font = font;
if(cell.halign == middle || thisLineCentered)
{
x = (left + right - lineW)/2;
x = Max(x, left);
}
else if(cell.halign == HorizontalAlignment::right)
{
x = right - lineW;
x = Max(x, left);
}
else
x = left;
lineH = Max(lineH, newLineH);
RenderLine(browser, surface, x, y, cellW, newLineH, block, textPos, nextCellBlock, nextCellPos, left, right);
if(changeLine)
{
//y += lineH;
//maxH -= lineH;
y += newLineH;
maxH -= newLineH;
//lineH = 0;
}
textPos = nextCellPos;
block = nextCellBlock;
}
//y += lineH;
//maxH -= lineH;
for(object = leftObjects.last; object; object = nextObject)
{
nextObject = object.prev;
y = Max(y, object.untilY);
leftObjects.Delete(object);
}
for(object = rightObjects.last; object; object = nextObject)
{
nextObject = object.prev;
y = Max(y, object.untilY);
rightObjects.Delete(object);
}
cell.parent = parent;
cell.next = next;
}
static void RenderRow(HTMLView browser, Surface surface, Block row, Block table, int x, int y)
{
Block cell;
int c = 0;
Column column = table.columns.first;
for(cell = row.subBlocks.first; cell; cell = cell.next)
{
if(cell.type == TD)
{
int c;
while(column && column.rowSpan)
column = column.next;
RenderCell(browser, surface, cell, x, y);
for(c = 0; c