about summary refs log tree commit diff stats
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-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 =