diff --git a/src/vaev-layout/flex.cpp b/src/vaev-layout/flex.cpp index a5e665c..2e164a9 100644 --- a/src/vaev-layout/flex.cpp +++ b/src/vaev-layout/flex.cpp @@ -150,12 +150,12 @@ struct FlexItem { // TODO: only implementing borders after border-box is finished // InsetsPx borders; - FlexItem(Tree &tree, Box &box, bool isRowOriented) + FlexItem(Tree &tree, Box &box, bool isRowOriented, Vec2Px containingBlock) : box(&box), flexItemProps(*box.style->flex), fa(isRowOriented) { - speculateValues(tree, Input{Commit::NO}); // intrinsic? + speculateValues(tree, Input{Commit::NO}); // TODO: not always we will need min/max content sizes, // this can be lazy computed for performance gains - computeContentSizes(tree); + computeContentSizes(tree, containingBlock); } void commit() { @@ -165,25 +165,9 @@ struct FlexItem { box->layout.margin.bottom = margin.bottom.unwrapOr(speculativeMargin.bottom); } - void computeContentSizes(Tree &tree) { - _speculateValues( - tree, - { - .commit = Commit::NO, - .intrinsic = IntrinsicSize::MAX_CONTENT, - .knownSize = {NONE, NONE}, - }, - maxContentSize - ); - _speculateValues( - tree, - { - .commit = Commit::NO, - .intrinsic = IntrinsicSize::MIN_CONTENT, - .knownSize = {NONE, NONE}, - }, - minContentSize - ); + void computeContentSizes(Tree &tree, Vec2Px containingBlock) { + minContentSize = computeIntrinsicSize(tree, *box, IntrinsicSize::MIN_CONTENT, containingBlock); + maxContentSize = computeIntrinsicSize(tree, *box, IntrinsicSize::MAX_CONTENT, containingBlock); } enum OuterPosition { @@ -276,10 +260,9 @@ struct FlexItem { void computeHypotheticalMainSize(Tree &tree, Vec2Px containerSize) { hypoMainSize = clamp( flexBaseSize, - getMinMaxPrefferedSize(tree, flexItemProps.isRowOriented(), true, containerSize), - getMinMaxPrefferedSize(tree, flexItemProps.isRowOriented(), false, containerSize) + getMinMaxPrefferedSize(tree, fa.isRowOriented, true, containerSize), + getMinMaxPrefferedSize(tree, fa.isRowOriented, false, containerSize) ); - hypoMainSize = flexBaseSize; } Px getMinMaxPrefferedSize(Tree &tree, bool isWidth, bool isMin, Vec2Px containerSize) const { @@ -340,11 +323,7 @@ struct FlexItem { // https://www.w3.org/TR/css-flexbox-1/#intrinsic-item-contributions Px getMainSizeMinMaxContentContribution(Tree &tree, bool isMin, Vec2Px containerSize) { - Px contentContribution; - if (isMin) - contentContribution = fa.mainAxis(minContentSize) + getMargin(BOTH_MAIN); - else - contentContribution = fa.mainAxis(maxContentSize) + getMargin(BOTH_MAIN); + Px contentContribution = fa.mainAxis(isMin ? minContentSize : maxContentSize) + getMargin(BOTH_MAIN); if (fa.mainAxis(box->style->sizing).type == Size::Type::LENGTH) { contentContribution = max( @@ -354,14 +333,13 @@ struct FlexItem { *box, fa.mainAxis(box->style->sizing).value, fa.mainAxis(containerSize) - ) + ) + getMargin(BOTH_MAIN) ); } else if (fa.mainAxis(box->style->sizing).type == Size::Type::MIN_CONTENT) { contentContribution = max(contentContribution, fa.mainAxis(minContentSize) + getMargin(BOTH_MAIN)); } else if (fa.mainAxis(box->style->sizing).type == Size::Type::AUTO and not isMin) { - contentContribution = fa.mainAxis(speculativeSize); - } else { - logWarn("not implemented"); + contentContribution = max(contentContribution, fa.mainAxis(speculativeSize)); + // contentContribution = max(contentContribution, fa.mainAxis(speculativeSize) + getMargin(BOTH_MAIN)); } if (flexItemProps.grow == 0) @@ -377,6 +355,29 @@ struct FlexItem { ); } + // unofficial + Px getCrossSizeMinMaxContentContribution(Tree &tree, bool isMin, Vec2Px containerSize) { + Px contentContribution = fa.crossAxis(isMin ? minContentSize : maxContentSize) + getMargin(BOTH_MAIN); + + if (fa.crossAxis(box->style->sizing).type == Size::Type::LENGTH) { + contentContribution = max( + contentContribution, + resolve( + tree, + *box, + fa.crossAxis(box->style->sizing).value, + fa.crossAxis(containerSize) + ) + getMargin(BOTH_CROSS) + ); + } + + return clamp( + contentContribution, + getMinMaxPrefferedSize(tree, not fa.isRowOriented, true, containerSize), + getMinMaxPrefferedSize(tree, not fa.isRowOriented, false, containerSize) + ); + } + void alignCrossFlexStart() { if (not hasAnyCrossMarginAuto()) { @@ -410,11 +411,9 @@ struct FlexItem { auto elementSpeculativeCrossSize = lineCrossSize - getMargin(BOTH_CROSS); speculateValues( tree, - {.commit = input.commit, - .intrinsic = input.intrinsic, - .knownSize = fa.extractMainAxisAndFillOptOther(usedSize, elementSpeculativeCrossSize), - // TODO: not really sure of these arguments, check specs - .availableSpace = fa.extractMainAxisAndFillOther(usedSize, elementSpeculativeCrossSize) + { + .commit = input.commit, + .knownSize = fa.extractMainAxisAndFillOptOther(usedSize, elementSpeculativeCrossSize), } ); @@ -547,10 +546,10 @@ struct FlexFormatingContext { Vec _items = {}; - void _generateAnonymousFlexItems(Tree &tree, Box &box) { + void _generateAnonymousFlexItems(Tree &tree, Box &box, Vec2Px containingBlock) { _items.ensure(box.children().len()); for (auto &c : box.children()) - _items.emplaceBack(tree, c, _flex.isRowOriented()); + _items.emplaceBack(tree, c, _flex.isRowOriented(), containingBlock); } // 2. MARK: Available main and cross space for the flex items -------------- @@ -559,33 +558,20 @@ struct FlexFormatingContext { Px _availableMainSpace = {}; Px _initiallyAvailableCrossSpace = {}; - void _determineCrossSpaceForIntrinsicSizes(Tree &t, Input input) { + void _determineCrossSpaceForIntrinsicSizes(Tree &tree, Input input) { // https://www.w3.org/TR/css-flexbox-1/#intrinsic-cross-sizes if (not _flex.isRowOriented() and _flex.wrap == FlexWrap::WRAP) { auto newInitiallyAvailableCrossSpace = Limits::MIN; - if (input.intrinsic == IntrinsicSize::MIN_CONTENT) { - for (auto &item : _items) { - newInitiallyAvailableCrossSpace = max( - newInitiallyAvailableCrossSpace, - item.getMainSizeMinMaxContentContribution( - t, - true, - fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) - ) - ); - } - } else if (input.intrinsic == IntrinsicSize::MAX_CONTENT) { - for (auto &item : _items) { - newInitiallyAvailableCrossSpace = max( - newInitiallyAvailableCrossSpace, - item.getMainSizeMinMaxContentContribution( - t, - false, - fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) - ) - ); - } + for (auto &item : _items) { + newInitiallyAvailableCrossSpace = max( + newInitiallyAvailableCrossSpace, + item.getCrossSizeMinMaxContentContribution( + tree, + input.intrinsic == IntrinsicSize::MIN_CONTENT, + fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) + ) + ); } _initiallyAvailableCrossSpace = newInitiallyAvailableCrossSpace; } @@ -602,8 +588,7 @@ struct FlexFormatingContext { _initiallyAvailableCrossSpace = input.knownSize.x.unwrapOr(input.availableSpace.x); } - if (input.intrinsic == IntrinsicSize::MIN_CONTENT or - input.intrinsic == IntrinsicSize::MAX_CONTENT) + if (isMinMaxIntrinsicSize(input.intrinsic)) _determineCrossSpaceForIntrinsicSizes(t, input); } @@ -611,7 +596,7 @@ struct FlexFormatingContext { // https://www.w3.org/TR/css-flexbox-1/#algo-main-item void _determineFlexBaseSizeAndHypotheticalMainSize( - Tree &tree, Input input + Tree &tree ) { for (auto &i : _items) { i.computeFlexBaseSize( @@ -632,7 +617,6 @@ struct FlexFormatingContext { tree, { .commit = Commit::NO, - .intrinsic = input.intrinsic, .knownSize = fa.extractMainAxisAndFillOptOther(i.flexBaseSize), .availableSpace = fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace), } @@ -645,98 +629,151 @@ struct FlexFormatingContext { Px _usedMainSize = {}; - void _determineMainSize(Input input) { - // TODO: we should have the knownSize of the main size; not clear what to do in case it isnt there - _usedMainSize = - _flex.isRowOriented() - ? input.knownSize.x.unwrapOr(Px{0}) - : input.knownSize.y.unwrapOr(Px{0}); - } + Vec _computeFlexFractions(Tree &t, Input input) { + Vec flexFraction; + for (auto &flexItem : _items) { + Px contribution = flexItem.getMainSizeMinMaxContentContribution( + t, + input.intrinsic == IntrinsicSize::MIN_CONTENT, + fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) + ); - // 5. MARK: Collect flex items into flex lines ----------------------------- - // https://www.w3.org/TR/css-flexbox-1/#algo-line-break + auto itemFlexFraction = (contribution - flexItem.flexBaseSize - flexItem.getMargin(FlexItem::BOTH_MAIN)); + + if (itemFlexFraction > Px{0}) + itemFlexFraction = itemFlexFraction / max(Px{1}, Px{flexItem.flexItemProps.grow}); + + else if (itemFlexFraction < Px{0}) + itemFlexFraction = itemFlexFraction / max(Px{1}, Px{flexItem.flexItemProps.shrink}); - Vec _lines = {}; + flexFraction.pushBack(itemFlexFraction); + } + return flexFraction; + } // https://www.w3.org/TR/css-flexbox-1/#intrinsic-main-sizes - void _collectFlexItemsInfoFlexLinesNoWrap(Tree &tree, Input input) { - _lines.emplaceBack(_items, fa.isRowOriented); + void _computeIntrinsicSize(Tree &t, Vec flexFraction) { - if (input.intrinsic == IntrinsicSize::MIN_CONTENT or - input.intrinsic == IntrinsicSize::MAX_CONTENT) { + usize globalIdx = 0; - Vec flexFraction; - for (auto &flexItem : _items) { - Px contribution = flexItem.getMainSizeMinMaxContentContribution( - tree, - input.intrinsic == IntrinsicSize::MIN_CONTENT, - fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) - ); + Px largestFraction{Limits::MIN}; - auto itemFlexFraction = (contribution - flexItem.flexBaseSize - flexItem.getMargin(FlexItem::BOTH_MAIN)); - if (itemFlexFraction > Px{0}) - itemFlexFraction = itemFlexFraction / max(Px{1}, Px{flexItem.flexItemProps.grow}); + // TODO: gonna need this when fragmenting + for (usize i = 0; i < _items.len(); ++i) { + largestFraction = max(largestFraction, flexFraction[globalIdx]); + globalIdx++; + } - else if (itemFlexFraction < Px{0}) - itemFlexFraction = itemFlexFraction / max(Px{1}, Px{flexItem.flexItemProps.shrink}); + Px sumOfProducts{0}; + for (auto &flexItem : _items) { + Px product{flexItem.flexBaseSize}; - flexFraction.pushBack(itemFlexFraction); + if (largestFraction < Px{0}) { + product += largestFraction / flexItem.getScaledFlexShrinkFactor(); + } else { + product += largestFraction * Px{flexItem.flexItemProps.grow}; } - Px largestSum = Limits::MIN; - usize globalIdx = 0; - for (auto &flexLine : _lines) { - Px largestFraction{Limits::MIN}; + sumOfProducts += clamp( + product, + flexItem.getMinMaxPrefferedSize(t, fa.isRowOriented, true, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)), + flexItem.getMinMaxPrefferedSize(t, fa.isRowOriented, false, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)) + ) + + flexItem.getMargin(FlexItem::BOTH_MAIN); + } + _usedMainSize = max(_usedMainSize, sumOfProducts); + } - for (usize i = 0; i < flexLine.items.len(); ++i) { - largestFraction = max(largestFraction, flexFraction[globalIdx]); - globalIdx++; - } + // https://github.com/w3c/csswg-drafts/issues/8884 + void _computeIntrinsicSizeRowNoWrap(Tree &t) { + _usedMainSize = Px{0}; + for (auto &flexItem : _items) { + auto minContrib = flexItem.getMainSizeMinMaxContentContribution( + t, + true, + fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) + ); - Px sumOfProducts{0}; - for (auto &flexItem : flexLine.items) { - Px product{flexItem.flexBaseSize}; + bool cantMove = flexItem.flexItemProps.grow == 0 and flexItem.flexBaseSize > minContrib; + cantMove |= flexItem.flexItemProps.shrink == 0 and flexItem.flexBaseSize < minContrib; - if (largestFraction < Px{0}) { - product += largestFraction / flexItem.getScaledFlexShrinkFactor(); - } else { - product += largestFraction * Px{flexItem.flexItemProps.grow}; - } + if (cantMove and true) + _usedMainSize += flexItem.flexBaseSize; + else + _usedMainSize += minContrib; + } + } - sumOfProducts += clamp( - product + flexItem.getMargin(FlexItem::BOTH_MAIN), - flexItem.getMinMaxPrefferedSize(tree, fa.isRowOriented, true, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)), - flexItem.getMinMaxPrefferedSize(tree, fa.isRowOriented, false, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)) - ); - } + void _computeIntrinsicSizeMinMultilineColumn(Tree &tree) { + Px largestMinContentContrib = Limits::MIN; + for (usize i = 0; i < _items.len(); ++i) { + auto &flexItem = _items[i]; - largestSum = max(largestSum, sumOfProducts); + largestMinContentContrib = max( + largestMinContentContrib, + flexItem.getMainSizeMinMaxContentContribution( + tree, + true, + fa.buildPair(_usedMainSize, _initiallyAvailableCrossSpace) + ) + ); + } + + _usedMainSize = max(_usedMainSize, largestMinContentContrib); + } + + void _determineMainSize(Tree &t, Input input, Box &box) { + _usedMainSize = + _flex.isRowOriented() + ? input.knownSize.x.unwrapOr(Px{0}) + : input.knownSize.y.unwrapOr(Px{0}); + + if (input.intrinsic == IntrinsicSize::MAX_CONTENT) { + if (fa.isRowOriented) { + if (_flex.wrap == FlexWrap::NOWRAP) + _computeIntrinsicSizeRowNoWrap(t); + else { + // NOTE: would be _computeIntrinsicSize(t, _computeFlexFractions(t, input)) per specs, but found + // different behaviour on Chrome + _computeIntrinsicSizeRowNoWrap(t); + } + } else + _computeIntrinsicSize(t, _computeFlexFractions(t, input)); + } + if (input.intrinsic == IntrinsicSize::MIN_CONTENT) { + if (fa.isRowOriented) { + if (_flex.wrap == FlexWrap::NOWRAP) + _computeIntrinsicSizeRowNoWrap(t); + else + _computeIntrinsicSizeMinMultilineColumn(t); + } else { + if (_flex.wrap == FlexWrap::NOWRAP) + _computeIntrinsicSize(t, _computeFlexFractions(t, input)); + else { + _computeIntrinsicSize(t, _computeFlexFractions(t, input)); + // Chrome's behaviour is to put all items in the same line, even if it is multiline column; thus we + // are not following specs and wont run _computeIntrinsicSizeMinMultilineColumn(t); + } } + } else if (not fa.isRowOriented) { + auto heightWrapSizing = box.style->sizing->height; - _usedMainSize = max(_usedMainSize, largestSum); + if (heightWrapSizing == Size::MAX_CONTENT or + heightWrapSizing == Size::MIN_CONTENT or + heightWrapSizing == Size::AUTO) + _computeIntrinsicSize(t, _computeFlexFractions(t, input)); } } - // https://www.w3.org/TR/css-flexbox-1/#intrinsic-main-sizes - void _collectFlexItemsInfoFlexLinesWrap(Tree &tree, Input input) { - if (input.intrinsic == IntrinsicSize::MIN_CONTENT) { + // 5. MARK: Collect flex items into flex lines ----------------------------- + // https://www.w3.org/TR/css-flexbox-1/#algo-line-break - Px largestMinContentContrib = Limits::MIN; - for (usize i = 0; i < _items.len(); ++i) { - auto &flexItem = _items[i]; + Vec + _lines = {}; - largestMinContentContrib = max( - largestMinContentContrib, - flexItem.getMainSizeMinMaxContentContribution( - tree, - true, - fa.buildPair(_usedMainSize, _initiallyAvailableCrossSpace) - ) + flexItem.getMargin(FlexItem::BOTH_MAIN) // FIX ME - ); - } + // https://www.w3.org/TR/css-flexbox-1/#intrinsic-main-sizes + void _collectFlexItemsInfoFlexLinesWrap() { - _usedMainSize = max(_usedMainSize, largestMinContentContrib); - } usize si = 0; while (si < _items.len()) { usize ei = si; @@ -744,17 +781,11 @@ struct FlexFormatingContext { Px currLineSize = Px{0}; while (ei < _items.len()) { - Px itemContribution = input.intrinsic != IntrinsicSize::MIN_CONTENT - ? _items[ei].hypoMainSize - : _items[ei].getMainSizeMinMaxContentContribution( - tree, - true, - fa.buildPair(_usedMainSize, _initiallyAvailableCrossSpace) - ); + Px itemContribution = _items[ei].hypoMainSize; itemContribution += _items[ei].getMargin(FlexItem::BOTH_MAIN); // TODO: ignoring breaks for now - if (currLineSize + itemContribution <= _usedMainSize or currLineSize == Px{0}) { + if (currLineSize + itemContribution <= _usedMainSize + Px{0.01} or currLineSize == Px{0}) { currLineSize += itemContribution; ei++; } else @@ -767,11 +798,12 @@ struct FlexFormatingContext { } } - void _collectFlexItemsIntoFlexLines(Tree &tree, Input input) { - if (_flex.wrap == FlexWrap::NOWRAP or input.intrinsic == IntrinsicSize::MAX_CONTENT) - _collectFlexItemsInfoFlexLinesNoWrap(tree, input); - else - _collectFlexItemsInfoFlexLinesWrap(tree, input); + void _collectFlexItemsIntoFlexLines() { + if (_flex.wrap == FlexWrap::NOWRAP) { + _lines.emplaceBack(_items, fa.isRowOriented); + } else { + _collectFlexItemsInfoFlexLinesWrap(); + } if (_flex.direction == FlexDirection::ROW_REVERSE) for (auto &flexLine : _lines) @@ -800,7 +832,8 @@ struct FlexFormatingContext { matchedSize or (flexCaseIsGrow and flexItem.flexBaseSize > flexItem.hypoMainSize) or (not flexCaseIsGrow and flexItem.flexBaseSize < flexItem.hypoMainSize) or - (flexItem.flexItemProps.grow == 0 and flexItem.flexItemProps.shrink == 0) + (flexItem.flexItemProps.grow == 0 and flexCaseIsGrow) or + (flexItem.flexItemProps.shrink == 0 and not flexCaseIsGrow) ) { fa.mainAxis(flexItem.usedSize) = flexItem.hypoMainSize; frozenItems.pushBack(&flexItem); @@ -934,33 +967,35 @@ struct FlexFormatingContext { for (auto &i : _items) { Px availableCrossSpace = _initiallyAvailableCrossSpace - i.getMargin(FlexItem::BOTH_CROSS); - if (fa.mainAxis(i.box->style->sizing) == Size::AUTO) + if (fa.mainAxis(i.box->style->sizing) == Size::AUTO || fa.crossAxis(i.box->style->sizing) == Size::AUTO) input.intrinsic = IntrinsicSize::STRETCH_TO_FIT; i.speculateValues( tree, { - .commit = input.commit, - .intrinsic = input.intrinsic, + .commit = Commit::NO, .knownSize = fa.extractMainAxisAndFillOptOther(i.usedSize), .availableSpace = fa.extractMainAxisAndFillOther(i.usedSize, availableCrossSpace), } ); + + // COMO PODE EU TER UM HEIGHT PEQUENO AQUI?????????? } } // 8. MARK: Calculate the cross size of each flex line --------------------- // https://www.w3.org/TR/css-flexbox-1/#intrinsic-cross-sizes - void _calculateCrossSizeOfEachFlexLineIntrinsicSize(Input input) { + void _calculateCrossSizeOfEachFlexLineIntrinsicSize(Tree &tree, Input input) { + for (auto &flexLine : _lines) { if (input.intrinsic == IntrinsicSize::MIN_CONTENT) for (auto &flexItem : flexLine.items) { - flexLine.crossSize = max(flexLine.crossSize, fa.crossAxis(flexItem.minContentSize) + flexItem.getMargin(FlexItem::BOTH_CROSS)); + flexLine.crossSize = max(flexLine.crossSize, flexItem.getCrossSizeMinMaxContentContribution(tree, true, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace))); } else for (auto &flexItem : flexLine.items) { - flexLine.crossSize = max(flexLine.crossSize, fa.crossAxis(flexItem.maxContentSize) + flexItem.getMargin(FlexItem::BOTH_CROSS)); + flexLine.crossSize = max(flexLine.crossSize, flexItem.getCrossSizeMinMaxContentContribution(tree, false, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace))); } } } @@ -1000,9 +1035,10 @@ struct FlexFormatingContext { } } - void _calculateCrossSizeOfEachFlexLine(Input input) { + void _calculateCrossSizeOfEachFlexLine(Tree &tree, Input input) { if (isMinMaxIntrinsicSize(input.intrinsic)) { - _calculateCrossSizeOfEachFlexLineIntrinsicSize(input); + _calculateCrossSizeOfEachFlexLineIntrinsicSize(tree, input); + // TODO: follow specs } else { _calculateCrossSizeOfEachFlexLineNonIntrinsicSize(input); } @@ -1013,9 +1049,11 @@ struct FlexFormatingContext { void _handleAlignContentStretch(Input input, Box &box) { // FIXME: If the flex container has a definite cross size <=?=> f.style->sizing->height.type != Size::Type::AUTO - if (not isMinMaxIntrinsicSize(input.intrinsic) and // FIXME - fa.crossAxis(box.style->sizing).type != Size::Type::AUTO and - box.style->aligns.alignContent == Style::Align::STRETCH) { + if ( + (not(input.intrinsic == IntrinsicSize::MIN_CONTENT) and true) and + (fa.crossAxis(box.style->sizing).type != Size::Type::AUTO or fa.crossAxis(input.knownSize)) and + box.style->aligns.alignContent == Style::Align::STRETCH + ) { Px sumOfCrossSizes{0}; for (auto &flexLine : _lines) sumOfCrossSizes += flexLine.crossSize; @@ -1045,15 +1083,12 @@ struct FlexFormatingContext { if (itemAlign == Style::Align::AUTO) itemAlign = box.style->aligns.alignItems; - if (input.intrinsic == IntrinsicSize::MIN_CONTENT) { - fa.crossAxis(flexItem.usedSize) = fa.crossAxis(flexItem.minContentSize); - } else if (input.intrinsic == IntrinsicSize::MAX_CONTENT) { - fa.crossAxis(flexItem.usedSize) = fa.crossAxis(flexItem.maxContentSize); - } else if ( + if ( itemAlign == Style::Align::STRETCH and - flexItem.box->style->sizing->height.type == Size::AUTO and + fa.crossAxis(flexItem.box->style->sizing).type == Size::AUTO and not flexItem.hasAnyCrossMarginAuto() ) { + fa.crossAxis(flexItem.usedSize) = flexLine.crossSize - flexItem.getMargin(FlexItem::BOTH_CROSS); fa.crossAxis(flexItem.usedSize) = clamp( @@ -1071,6 +1106,10 @@ struct FlexFormatingContext { fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace) ) ); + } else if (input.intrinsic == IntrinsicSize::MIN_CONTENT) { + fa.crossAxis(flexItem.usedSize) = flexItem.getCrossSizeMinMaxContentContribution(tree, true, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)); + } else if (input.intrinsic == IntrinsicSize::MAX_CONTENT) { + fa.crossAxis(flexItem.usedSize) = flexItem.getCrossSizeMinMaxContentContribution(tree, false, fa.buildPair(_availableMainSpace, _initiallyAvailableCrossSpace)); } else { fa.crossAxis(flexItem.usedSize) = fa.crossAxis(flexItem.speculativeSize); } @@ -1152,6 +1191,7 @@ struct FlexFormatingContext { bool endCrossMarginIsAuto = fa.endCrossAxis(marginStyle) == Width::AUTO; if (startCrossMarginIsAuto or endCrossMarginIsAuto) { + if (fa.crossAxis(i.usedSize) + i.getMargin(FlexItem::BOTH_CROSS) < l.crossSize) { if (not startCrossMarginIsAuto and endCrossMarginIsAuto) { auto startMargin = i.getMargin(FlexItem::START_CROSS); @@ -1203,11 +1243,12 @@ struct FlexFormatingContext { Px _usedCrossSizeByLines{0}; Px _usedCrossSize{0}; - void _determineFlexContainerUsedCrossSize(Input input) { - for (auto &flexLine : _lines) + void _determineFlexContainerUsedCrossSize(Input input, Box &box) { + for (auto &flexLine : _lines) { _usedCrossSizeByLines += flexLine.crossSize; + } - if (isMinMaxIntrinsicSize(input.intrinsic)) + if (isMinMaxIntrinsicSize(input.intrinsic) or fa.crossAxis(box.style->sizing) == Size::Type::AUTO) _usedCrossSize = _usedCrossSizeByLines; else if (fa.crossAxis(input.knownSize)) _usedCrossSize = fa.crossAxis(input.knownSize).unwrap(); @@ -1307,12 +1348,12 @@ struct FlexFormatingContext { *flexItem.box, { .commit = Commit::YES, - .intrinsic = input.intrinsic, .knownSize = {flexItem.usedSize.x, flexItem.usedSize.y}, .position = flexItem.position, .availableSpace = flexItem.usedSize, } ); + flexItem.commit(); } } @@ -1323,19 +1364,19 @@ struct FlexFormatingContext { // FIXME: auto, min and max content values for flex container dimensions are not working as in Chrome; add tests Output run(Tree &tree, Box &box, Input input) { // 1. Generate anonymous flex items - _generateAnonymousFlexItems(tree, box); + _generateAnonymousFlexItems(tree, box, input.containingBlock); // 2. Determine the available main and cross space for the flex items. _determineAvailableMainAndCrossSpace(tree, input); // 3. Determine the flex base size and hypothetical main size of each item - _determineFlexBaseSizeAndHypotheticalMainSize(tree, input); + _determineFlexBaseSizeAndHypotheticalMainSize(tree); // 4. Determine the main size of the flex container - _determineMainSize(input); + _determineMainSize(tree, input, box); // 5. Collect flex items into flex lines - _collectFlexItemsIntoFlexLines(tree, input); + _collectFlexItemsIntoFlexLines(); // 6. Resolve the flexible lengths _resolveFlexibleLengths(tree); @@ -1344,7 +1385,7 @@ struct FlexFormatingContext { _determineHypotheticalCrossSize(tree, input); // 8. Calculate the cross size of each flex line - _calculateCrossSizeOfEachFlexLine(input); + _calculateCrossSizeOfEachFlexLine(tree, input); // 9. Handle 'align-content: stretch'. _handleAlignContentStretch(input, box); @@ -1365,7 +1406,7 @@ struct FlexFormatingContext { _alignAllFlexItems(tree, box, input); // 15. Determine the flex container's used cross size - _determineFlexContainerUsedCrossSize(input); + _determineFlexContainerUsedCrossSize(input, box); // 16. Align all flex lines _alignAllFlexLines(box); @@ -1378,12 +1419,13 @@ struct FlexFormatingContext { } }; -Output flexLayout(Tree &t, Box &box, Input input) { +Output flexLayout(Tree &tree, Box &box, Input input) { FlexFormatingContext fc = { ._flex = *box.style->flex, - .fa = box.style->flex->isRowOriented() + .fa = box.style->flex->isRowOriented(), }; - return fc.run(t, box, input); + + return fc.run(tree, box, input); } } // namespace Vaev::Layout