about summary refs log tree commit diff stats
path: root/src/layout/engine.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-07-08 22:19:18 +0200
committerbptato <nincsnevem662@gmail.com>2023-07-08 22:24:23 +0200
commit121dae79083b43b0fde41c143747a23318b17a95 (patch)
treeda9404a8499d2578715a6fd12378cf68b16a364e /src/layout/engine.nim
parent51603f8865063d39c99dde10ba89528a7ed312c5 (diff)
downloadchawan-121dae79083b43b0fde41c143747a23318b17a95.tar.gz
layout: width-related fixes
* Set contentWidthInfinite to false when specified width commands so
* Unify applyWidth of block boxes. probably still incorrect, just less so
  (at least we no longer have two slightly different cases...)

This appears to fix some infinite table cell width issues.
Diffstat (limited to 'src/layout/engine.nim')
-rw-r--r--src/layout/engine.nim72
1 files changed, 38 insertions, 34 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 144f9102..ca51faae 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -442,6 +442,7 @@ proc resolveDimensions(box: BlockBox, availableWidth: LayoutUnit,
   let widthpx = computed{"width"}.px(viewport, availableWidth)
   if computed{"width"}.auto:
     box.contentWidth = availableWidth
+    box.contentWidthInfinite = false
   else:
     box.contentWidth = widthpx
     box.max_width = some(widthpx)
@@ -453,6 +454,7 @@ proc resolveDimensions(box: BlockBox, availableWidth: LayoutUnit,
     if max_width < box.contentWidth:
       box.contentWidth = max_width
       box.resolveContentWidth(max_width, availableWidth)
+    box.contentWidthInfinite = false
   if not computed{"min-width"}.auto:
     let min_width = computed{"min-width"}.px(viewport, availableWidth)
     box.min_width = some(min_width)
@@ -632,6 +634,24 @@ proc buildBlocks(parent: BlockBox, blocks: seq[BoxBuilder], node: StyledNode)
 proc buildTable(builder: TableBoxBuilder, parent: BlockBox): BlockBox
 proc buildTableLayout(table: BlockBox, builder: TableBoxBuilder)
 
+proc applyWidth(box: BlockBox, maxChildWidth: LayoutUnit) =
+  box.width = if box.computed{"width"}.auto:
+    # Make the box as small/large as the content's width.
+    if box.shrink:
+      if box.contentWidthInfinite:
+        maxChildWidth
+      else:
+        min(maxChildWidth, box.contentWidth)
+    else:
+      box.contentWidth
+  else:
+    # Not much choice is left here.
+    box.contentWidth
+  # Add padding.
+  # Then, clamp it to min_width and max_width (if applicable).
+  box.width = clamp(box.width, box.min_width.get(0),
+    box.max_width.get(high(LayoutUnit)))
+
 proc applyInlineDimensions(box: BlockBox) =
   box.xminwidth = max(box.xminwidth, box.inline.minwidth)
   box.width = box.inline.width + box.padding_left + box.padding_right
@@ -642,17 +662,9 @@ proc applyInlineDimensions(box: BlockBox) =
   box.height += box.padding_top + box.padding_bottom
   box.inline.offset.x += box.padding_left
   box.inline.offset.y += box.padding_top
-  box.width = if not box.isWidthSpecified():
-    # We can make the box as small/large as the content's width.
-    if box.shrink:
-      if box.contentWidthInfinite:
-        box.width
-      else:
-        min(box.width, box.contentWidth)
-    else:
-      max(box.width, box.contentWidth)
-  else:
-    min(max(box.width, box.min_width.get(0)), box.max_width.get(high(int)))
+  box.applyWidth(box.inline.width)
+  box.width += box.padding_left
+  box.width += box.padding_right
 
 # Builder only contains inline boxes.
 proc buildInlineLayout(parent: BlockBox, children: seq[BoxBuilder]) =
@@ -834,7 +846,8 @@ proc positionRelative(parent, box: BlockBox) =
     box.offset.y -= parent.height - bottom.px(parent.viewport) - box.height
 
 proc applyChildPosition(parent, child: BlockBox, spec: bool,
-    x, y: var LayoutUnit, margin_todo: var Strut) =
+    x, y: var LayoutUnit, margin_todo: var Strut,
+    maxChildWidth: var LayoutUnit) =
   if child.computed{"position"} == POSITION_ABSOLUTE: #TODO sticky, fixed
     if child.computed{"left"}.auto and child.computed{"right"}.auto:
       child.offset.x = x
@@ -846,11 +859,7 @@ proc applyChildPosition(parent, child: BlockBox, spec: bool,
     child.offset.x = x
     y += child.height
     parent.height += child.height
-    if not spec:
-      parent.width = if parent.contentWidthInfinite:
-        max(child.width, parent.width)
-      else:
-        min(parent.contentWidth, max(child.width, parent.width))
+    maxChildWidth = max(maxChildWidth, child.width)
     parent.xminwidth = max(parent.xminwidth, child.xminwidth)
     margin_todo = Strut()
     margin_todo.append(child.margin_bottom)
@@ -868,15 +877,9 @@ proc postAlignChild(box, child: BlockBox, width: LayoutUnit, spec: bool) =
 proc positionBlocks(box: BlockBox) =
   var y: LayoutUnit = 0
   var x: LayoutUnit = 0
+  var maxChildWidth: LayoutUnit
   var margin_todo: Strut
 
-  # If content width has been specified, use it.
-  # Otherwise, contentWidth is just the maximum width we can take up, so
-  # set width to box.contentWidth
-  let spec = box.isWidthSpecified()
-  if spec:
-    box.width = box.contentWidth
-
   y += box.padding_top
   box.height += box.padding_top
   x += box.padding_left
@@ -886,7 +889,7 @@ proc positionBlocks(box: BlockBox) =
     let child = box.nested[i]
     if child.computed{"position"} != POSITION_ABSOLUTE:
       break
-    applyChildPosition(box, child, spec, x, y, margin_todo)
+    applyChildPosition(box, child, spec, x, y, margin_todo, maxChildWidth)
     inc i
 
   if i < box.nested.len:
@@ -894,7 +897,7 @@ proc positionBlocks(box: BlockBox) =
     margin_todo.append(box.margin_top)
     margin_todo.append(child.margin_top)
     box.margin_top = margin_todo.sum()
-    applyChildPosition(box, child, spec, x, y, margin_todo)
+    applyChildPosition(box, child, spec, x, y, margin_todo, maxChildWidth)
     inc i
 
   while i < box.nested.len:
@@ -903,19 +906,18 @@ proc positionBlocks(box: BlockBox) =
       margin_todo.append(child.margin_top)
       y += margin_todo.sum()
       box.height += margin_todo.sum()
-    applyChildPosition(box, child, spec, x, y, margin_todo)
+    applyChildPosition(box, child, spec, x, y, margin_todo, maxChildWidth)
     inc i
 
   margin_todo.append(box.margin_bottom)
   box.margin_bottom = margin_todo.sum()
 
+  box.applyWidth(maxChildWidth)
+
   # Re-position the children.
   # The x offset for values in shrink mode depends on the parent box's
   # width, so we cannot do this in the first pass.
-  let width = if box.shrink:
-    min(box.width, box.contentWidth)
-  else:
-    max(box.width, box.contentWidth)
+  let width = box.width
   for child in box.nested:
     if child.computed{"position"} != POSITION_ABSOLUTE:
       box.postAlignChild(child, width, spec)
@@ -926,6 +928,11 @@ proc positionBlocks(box: BlockBox) =
       positionAbsolute(child)
     else: discard #TODO
 
+  # Finally, add padding. (We cannot do this further up without influencing
+  # positioning.)
+  box.width += box.padding_left
+  box.width += box.padding_right
+
   box.height += box.padding_bottom
 
   if box.contentHeight.isSome:
@@ -935,9 +942,6 @@ proc positionBlocks(box: BlockBox) =
   if box.min_height.isSome and box.height < box.min_height.get:
     box.height = box.min_height.get
 
-  box.width += box.padding_left
-  box.width += box.padding_right
-
 proc buildTableCaption(viewport: Viewport, builder: TableCaptionBoxBuilder,
     maxwidth: LayoutUnit, maxheight: Option[LayoutUnit], shrink = false):
     BlockBox =