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; bool centered = false; 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) { bool centered = false; 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; void * font = surface.GetFont(); // 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; newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, ¢ered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0); surface.TextFont(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