about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/layout/engine.nim45
-rw-r--r--test/layout/flex-shrink-overconstrained.color.expected6
-rw-r--r--test/layout/flex-shrink-overconstrained.html6
-rw-r--r--test/layout/flex-shrink-simple.expected5
-rw-r--r--test/layout/non-growing-flex-item-indefinite-intrinsic-size.color.expected2
-rw-r--r--test/layout/non-growing-flex-item-indefinite-intrinsic-size.html11
-rw-r--r--todo3
7 files changed, 60 insertions, 18 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 9ba6ffd2..900e5062 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -1111,9 +1111,10 @@ proc resolveFlexItemSizes(lctx: LayoutContext; space: AvailableSpace;
   if length.canpx(space[dim]):
     let u = length.spx(lctx, space[dim], computed, paddingSum[dim])
     sizes.space[dim] = stretch(minClamp(u, sizes.minMaxSizes[dim]))
-  elif sizes.space[dim].isDefinite():
-    let u = sizes.space[dim].u - sizes.margin[dim].sum() - paddingSum[dim]
-    sizes.space[dim] = fitContent(minClamp(u, sizes.minMaxSizes[dim]))
+  else:
+    # Ensure that space is indefinite in the first pass if no width has
+    # been specified.
+    sizes.space[dim] = maxContent()
   let odim = dim.opposite()
   let olength = computed[CvalSizeMap[odim]].length
   if olength.canpx(space[odim]):
@@ -1380,6 +1381,8 @@ proc positionFloats(bctx: var BlockContext) =
   bctx.unpositionedFloats.setLen(0)
 
 proc layoutInline(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
+  if box.computed{"position"} notin PositionStaticLike:
+    bctx.lctx.pushPositioned()
   let bfcOffset = if bctx.parentBps != nil:
     bctx.parentBps.offset + box.state.offset
   else: # this block establishes a new BFC.
@@ -1435,6 +1438,8 @@ proc layoutInline(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
   box.state.baseline = ictx.state.baseline
   box.state.firstBaseline = ictx.state.firstBaseline
   box.state.overflow = ictx.state.overflow
+  if box.computed{"position"} notin PositionStaticLike:
+    bctx.lctx.popPositioned(box.state.overflow, box.state.size)
   box.state.overflow.finalize(box.state.size)
 
 proc layoutFlow(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
@@ -2220,6 +2225,7 @@ type
   FlexMainContext = object
     totalSize: Size
     maxSize: Size
+    shrinkSize: LayoutUnit
     maxMargin: RelativeRect
     totalWeight: array[FlexWeightType, float64]
     pending: seq[FlexPendingItem]
@@ -2254,7 +2260,13 @@ proc redistributeMainSize(mctx: var FlexMainContext; sizes: ResolvedSizes;
         totalWeight > 0:
       # redo maxSize calculation; we only need height here
       mctx.maxSize[odim] = 0
-      let unit = diff.toFloat64() / totalWeight
+      var udiv = totalWeight
+      if wt == fwtShrink:
+        udiv *= mctx.shrinkSize.toFloat64() / totalWeight
+      let unit = if udiv != 0:
+        diff.toFloat64() / udiv
+      else:
+        0
       # reset total weight & available diff for the next iteration (if there is
       # one)
       totalWeight = 0
@@ -2263,8 +2275,10 @@ proc redistributeMainSize(mctx: var FlexMainContext; sizes: ResolvedSizes;
         if it.weights[wt] == 0:
           mctx.updateMaxSizes(it.child, it.sizes)
           continue
-        var u = it.child.state.size[dim] +
-          (unit * it.weights[wt]).toLayoutUnit()
+        var uw = unit * it.weights[wt]
+        if wt == fwtShrink:
+          uw *= it.child.state.size[dim].toFloat64()
+        var u = it.child.state.size[dim] + uw.toLayoutUnit()
         # check for min/max violation
         var minu = it.sizes.minMaxSizes[dim].start
         minu = max(it.child.state.minFlexItemSize(dim), minu)
@@ -2273,6 +2287,7 @@ proc redistributeMainSize(mctx: var FlexMainContext; sizes: ResolvedSizes;
           if wt == fwtShrink: # freeze
             diff += u - minu
             it.weights[wt] = 0
+            mctx.shrinkSize -= it.child.state.size[dim]
           u = minu
         let maxu = it.sizes.minMaxSizes[dim].send
         if maxu < u:
@@ -2334,16 +2349,17 @@ proc layoutFlex(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
     var childSizes = lctx.resolveFlexItemSizes(sizes.space, dim, child.computed)
     let flexBasis = child.computed{"flex-basis"}
     lctx.layoutFlexChild(child, childSizes)
-    if not flexBasis.auto and childSizes.space[dim].isDefinite:
-      # we can't skip this pass; the first pass is needed to calculate the
-      # minimum height.
+    if not flexBasis.auto and sizes.space[dim].isDefinite:
+      # we can't skip this pass; it is needed to calculate the minimum
+      # height.
       let minu = child.state.minFlexItemSize(dim)
       childSizes.space[dim] = stretch(flexBasis.spx(lctx, sizes.space[dim],
         child.computed, childSizes.padding[dim].sum()))
       if minu > childSizes.space[dim].u:
-        # First pass gave us a box that is smaller than the minimum acceptable
-        # width whatever reason; this may have happened because the initial flex
-        # basis was e.g. 0. Try to resize it to something more usable.
+        # First pass gave us a box that is thinner than the minimum
+        # acceptable width for whatever reason; this may have happened
+        # because the initial flex basis was e.g. 0. Try to resize it to
+        # something more usable.
         childSizes.space[dim] = stretch(minu)
       lctx.layoutFlexChild(child, childSizes)
     if child.computed{"position"} in {PositionAbsolute, PositionFixed}:
@@ -2354,12 +2370,15 @@ proc layoutFlex(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
         sizes.space[dim].isDefinite and
         mctx.totalSize[dim] + child.state.size[dim] > sizes.space[dim].u):
       fctx.flushMain(mctx, sizes, dim)
-    mctx.totalSize[dim] += child.outerSize(dim, childSizes)
+    let outerSize = child.outerSize(dim, childSizes)
     mctx.updateMaxSizes(child, childSizes)
     let grow = child.computed{"flex-grow"}
     let shrink = child.computed{"flex-shrink"}
     mctx.totalWeight[fwtGrow] += grow
     mctx.totalWeight[fwtShrink] += shrink
+    mctx.totalSize[dim] += outerSize
+    if shrink != 0:
+      mctx.shrinkSize += outerSize
     mctx.pending.add(FlexPendingItem(
       child: child,
       weights: [grow, shrink],
diff --git a/test/layout/flex-shrink-overconstrained.color.expected b/test/layout/flex-shrink-overconstrained.color.expected
new file mode 100644
index 00000000..82c615f0
--- /dev/null
+++ b/test/layout/flex-shrink-overconstrained.color.expected
@@ -0,0 +1,6 @@
+1111 1111    test test test test test   
+1111 1111    test test test test test   
+1111 1111    test test test test test   
+1111 1111    test test                  
+1111                                    
+
diff --git a/test/layout/flex-shrink-overconstrained.html b/test/layout/flex-shrink-overconstrained.html
new file mode 100644
index 00000000..162bcb49
--- /dev/null
+++ b/test/layout/flex-shrink-overconstrained.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<div style="display: flex; width: 40ch">
+<div style="width: 40ch; background: red">1111 1111 1111 1111 1111 1111 1111 1111 1111</div>
+<div style="width: 80ch; background: pink">test test test test test test test test test test test test test test test test test</div>
+<!--
+<div style="width: 4ch; background: aliceblue">last</div>
diff --git a/test/layout/flex-shrink-simple.expected b/test/layout/flex-shrink-simple.expected
index 1ba2dc37..f694b6e7 100644
--- a/test/layout/flex-shrink-simple.expected
+++ b/test/layout/flex-shrink-simple.expected
@@ -1,3 +1,2 @@
-test test test test test test test test test test test test test test test  last
-test test test test test test test test test test
-test
+test test test test test  test test test test test test test test test test last
+test test test test       test test test test test test test
diff --git a/test/layout/non-growing-flex-item-indefinite-intrinsic-size.color.expected b/test/layout/non-growing-flex-item-indefinite-intrinsic-size.color.expected
new file mode 100644
index 00000000..a974ea54
--- /dev/null
+++ b/test/layout/non-growing-flex-item-indefinite-intrinsic-size.color.expected
@@ -0,0 +1,2 @@
+flex item 1a 
+     absolute
diff --git a/test/layout/non-growing-flex-item-indefinite-intrinsic-size.html b/test/layout/non-growing-flex-item-indefinite-intrinsic-size.html
new file mode 100644
index 00000000..6281e3fe
--- /dev/null
+++ b/test/layout/non-growing-flex-item-indefinite-intrinsic-size.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<div style="display: flex">
+<div>flex item 1</div>
+<div style="position: relative; background: pink">
+<div style="display: inline-block; width: 100%; background: red">a</div>
+<!--
+this part is a more or less unrelated test for whether setting relative
+on an inline root block box marks it as the containing block.
+-->
+<div style="right: 0; position: absolute">
+absolute
diff --git a/todo b/todo
index 8e107b1e..439b6cc4 100644
--- a/todo
+++ b/todo
@@ -54,8 +54,7 @@ layout engine:
 	* will probably need special treatment, as borders must round to
 	  1ch in x direction and 1em in y direction.
 - table layout: include caption in width calculation
-- flexbox: align-self, align-items, justify-content, proper margin handling,
-  proper flex base size resolution
+- flexbox: align-self, align-items, justify-content, proper margin handling
 - details element
 - overflow
 - partial layout, layout caching