about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-05-08 00:26:52 +0200
committerbptato <nincsnevem662@gmail.com>2024-05-08 00:41:30 +0200
commit58911a695800459597bd6193377a548e531a2319 (patch)
tree51437dc0168d430f9b079e38afa765269fc80980
parent22f3172c5cf6dbbcf63d1f249d1794a74ef7b497 (diff)
downloadchawan-58911a695800459597bd6193377a548e531a2319.tar.gz
layout: resize over-constrained table columns
If the total specified column width is larger than the table's allowed
width, we now resize them proportionally to the specified width.

This is quite important because many tables set the width to e.g. 50%
for "give me half of the table", instead of its true meaning "give me
half of the page".
-rw-r--r--src/layout/engine.nim36
-rw-r--r--todo3
2 files changed, 24 insertions, 15 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index da24465c..fae37f28 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -1819,7 +1819,7 @@ proc alignTableCell(cell: BlockBox; availableHeight, baseline: LayoutUnit) =
   else:
     cell.offset.y = baseline - cell.firstBaseline
 
-proc buildTableRow(pctx: TableContext; ctx: RowContext; parent: BlockBox;
+proc layoutTableRow(pctx: TableContext; ctx: RowContext; parent: BlockBox;
     builder: TableRowBoxBuilder): BlockBox =
   var x: LayoutUnit = 0
   var n = 0
@@ -1938,23 +1938,26 @@ proc preBuildTableRows(ctx: var TableContext; builder: TableBoxBuilder;
   ctx.preBuildTableRows(tfoot, table)
 
 proc calcUnspecifiedColIndices(ctx: var TableContext; W: var LayoutUnit;
-    weight: var float64): seq[int] =
+    weight: var float64; specifiedRatio: LayoutUnit): seq[int] =
   # Spacing for each column:
   var avail = newSeqUninitialized[int](ctx.cols.len)
   var j = 0
-  for i in 0 ..< ctx.cols.len:
-    if not ctx.cols[i].wspecified:
+  for i, col in ctx.cols.mpairs:
+    if not col.wspecified:
       avail[j] = i
-      let colw = ctx.cols[i].width
+      let colw = col.width
       let w = if colw < W:
         toFloat64(colw)
       else:
         toFloat64(W) * (ln(toFloat64(colw) / toFloat64(W)) + 1)
-      ctx.cols[i].weight = w
+      col.weight = w
       weight += w
       inc j
     else:
-      W -= ctx.cols[i].width
+      if specifiedRatio < 1:
+        col.width *= specifiedRatio
+        ctx.reflow[i] = true
+      W -= col.width
       avail.del(j)
   return avail
 
@@ -1974,8 +1977,17 @@ proc redistributeWidth(ctx: var TableContext) =
   var W = ctx.space.w.u
   # Remove inline spacing from distributable width.
   W -= ctx.cols.len * ctx.inlinespacing * 2
-  var weight: float64
-  var avail = ctx.calcUnspecifiedColIndices(W, weight)
+  var weight = 0f64
+  var totalSpecified: LayoutUnit = 0
+  for col in ctx.cols:
+    if col.wspecified:
+      totalSpecified += col.width
+    else:
+      # Hack: reserve the minimum space needed for unspecified columns,
+      # like other browsers do.
+      totalSpecified += col.minwidth
+  let specifiedRatio = if totalSpecified != 0: W / totalSpecified else: 1
+  var avail = ctx.calcUnspecifiedColIndices(W, weight, specifiedRatio)
   var redo = true
   while redo and avail.len > 0 and weight != 0:
     if weight == 0: break # zero weight; nothing to distribute
@@ -2012,13 +2024,13 @@ proc reflowTableCells(ctx: var TableContext) =
           ctx.reflow[n] = true
         dec n
 
-proc buildTableRows(ctx: TableContext; table: BlockBox; sizes: ResolvedSizes) =
+proc layoutTableRows(ctx: TableContext; table: BlockBox; sizes: ResolvedSizes) =
   var y: LayoutUnit = 0
   for roww in ctx.rows:
     if roww.builder.computed{"visibility"} == VisibilityCollapse:
       continue
     y += ctx.blockspacing
-    let row = ctx.buildTableRow(roww, table, roww.builder)
+    let row = ctx.layoutTableRow(roww, table, roww.builder)
     row.offset.y += y
     row.offset.x += sizes.padding.left
     row.size.w += sizes.padding.left
@@ -2077,7 +2089,7 @@ proc layoutTable(lctx: LayoutState; table: BlockBox; builder: TableBoxBuilder;
   for col in ctx.cols:
     table.size.w += col.width
   ctx.reflowTableCells()
-  ctx.buildTableRows(table, sizes)
+  ctx.layoutTableRows(table, sizes)
   if ctx.caption != nil:
     ctx.addTableCaption(table)
 
diff --git a/todo b/todo
index 71c85e46..32099bff 100644
--- a/todo
+++ b/todo
@@ -60,9 +60,6 @@ layout engine:
 - box borders
 	* will probably need special treatment, as borders must round to
 	  1ch in x direction and 1em in y direction.
-- make table width calculation consistent with FF etc.
-	* unfortunately, most websites are designed for auto table layouts
-	  where w3m's space distribution algorithm does not work really well :/
 - do not break inline boxes with out-of-flow block boxes (float, absolute, etc.)
 	* this seems hard to fix properly :(
 	* reminder: this does *not* apply to flexbox; in fact it has the inverse