Changeset 277222 in webkit
- Timestamp:
- May 7, 2021 6:48:22 PM (15 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/flexbox/flex-column-with-percent-height-descendants-expected.html (added)
-
LayoutTests/fast/flexbox/flex-column-with-percent-height-descendants.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/rendering/RenderFlexibleBox.cpp (modified) (5 diffs)
-
Source/WebCore/rendering/RenderFlexibleBox.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r277216 r277222 1 2021-05-07 Zalan Bujtas <zalan@apple.com> 2 3 [css-flexbox] Flex item construction may affect sibling flex item height computation 4 https://bugs.webkit.org/show_bug.cgi?id=225489 5 6 Reviewed by Sergio Villar Senin. 7 8 * fast/flexbox/flex-column-with-percent-height-descendants-expected.html: Added. 9 * fast/flexbox/flex-column-with-percent-height-descendants.html: Added. 10 1 11 2021-05-07 Amir Mark Jr <amir_mark@apple.com> 2 12 -
trunk/Source/WebCore/ChangeLog
r277203 r277222 1 2021-05-07 Zalan Bujtas <zalan@apple.com> 2 3 [css-flexbox] Flex item construction may affect sibling flex item height computation 4 https://bugs.webkit.org/show_bug.cgi?id=225489 5 6 Reviewed by Sergio Villar Senin. 7 8 Flex item construction triggers layout both on the flex item and on its descendants (see constructFlexItem). 9 During this layout a percent height descendant may indirectly set an incorrect value on the flex container's 10 m_hasDefiniteHeight (this is due to the odd way we choose to resolve percent height values on the ancestor chain, 11 see setOverridingContainingBlockContentLogicalHeight(WTF::nullopt)). 12 Now this incorrect m_hasDefiniteHeight value (Indefinite) causes the next sibling's (also) percent height 13 resolve fail as it tells the flex item that the flex container can't help with resolving the percent height value. 14 As the result we end up with an incorrect, 0px height value for this sibling. 15 e.g. 16 <div style="height: 100px; display: flex; flex-direction: column;"> 17 <div id=flexItemA style="height: 50px;"><div style="height: 100%;"></div></div> 18 <div id=flexItemB style="height: 50%;"></div> 19 </div> 20 By the time we get to the construction of flexItemB, the RenderFlexibleBox's (flex container) m_hasDefiniteHeight 21 is already (and incorrectly) set to Indefinite as the result of us trying to resolve flexItemA's descendant height percentage. 22 This Indefinite value makes the flexItemB's height resolution fail as we believe that the flex container has indefinite height 23 e.g "height: auto", while it is clearly resolvable (50% of 100px). 24 Now if we flip the order and flexItemB comes first, the test case passes fine. 25 It is very unfortunate that some descendant height resolving process can trigger a state change on the ancestor RenderFlexibleBox, but 26 fixing it would certainly require some substantial architectural change (e.g. pushing down the constraints to the geometry functions instead of 27 walking the containing block chain). 28 In this patch, we just scope m_hasDefiniteHeight so that the RenderFlexibleBox's state is not effected by the flex item construction. 29 30 Test: fast/flexbox/flex-column-with-percent-height-descendants.html 31 32 * rendering/RenderFlexibleBox.cpp: 33 (WebCore::RenderFlexibleBox::layoutFlexItems): 34 1 35 2021-05-07 Devin Rousso <drousso@apple.com> 2 36 -
trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp
r276835 r277222 269 269 m_relaidOutChildren.clear(); 270 270 271 bool oldInLayout = m_inLayout;272 m_inLayout = true;273 274 271 if (recomputeLogicalWidth()) 275 272 relayoutChildren = true; … … 322 319 323 320 clearNeedsLayout(); 324 325 m_inLayout = oldInLayout;326 321 } 327 322 … … 846 841 return false; 847 842 bool definite = child.computePercentageLogicalHeight(flexBasis, updateDescendants).hasValue(); 848 if ( m_inLayout&& (isHorizontalWritingMode() == child.isHorizontalWritingMode())) {843 if (!m_inFlexItemConstruction && (isHorizontalWritingMode() == child.isHorizontalWritingMode())) { 849 844 // We can reach this code even while we're not laying ourselves out, such 850 845 // as from mainSizeForPercentageResolution. … … 966 961 // should work off this list of a subset. 967 962 // TODO(cbiesinger): That second part is not yet true. 968 Vector<FlexItem> allItems; 969 m_orderIterator.first(); 970 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) { 971 if (m_orderIterator.shouldSkipChild(*child)) { 972 // Out-of-flow children are not flex items, so we skip them here. 973 if (child->isOutOfFlowPositioned()) 974 prepareChildForPositionedLayout(*child); 975 continue; 976 } 977 allItems.append(constructFlexItem(*child, relayoutChildren)); 978 } 979 980 // constructFlexItem() might set the override containing block height so any value cached for definiteness might be incorrect. 981 m_hasDefiniteHeight = SizeDefiniteness::Unknown; 982 963 auto allItems = constructFlexItems(relayoutChildren); 983 964 const LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max()); 984 965 LayoutUnit gapBetweenItems = computeGap(GapType::BetweenItems); … … 1295 1276 } 1296 1277 1297 FlexItem RenderFlexibleBox::constructFlexItem(RenderBox& child, bool relayoutChildren) 1298 { 1299 child.clearOverridingContentSize(); 1300 if (childHasIntrinsicMainAxisSize(child)) { 1301 // If this condition is true, then computeMainAxisExtentForChild will call 1302 // child.intrinsicContentLogicalHeight() and child.scrollbarLogicalHeight(), 1303 // so if the child has intrinsic min/max/preferred size, run layout on it now to make sure 1304 // its logical height and scroll bars are up to date. 1305 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); 1306 // Don't resolve percentages in children. This is especially important for the min-height calculation, 1307 // where we want percentages to be treated as auto. For flex-basis itself, this is not a problem because 1308 // by definition we have an indefinite flex basis here and thus percentages should not resolve. 1309 if (child.needsLayout() || !m_intrinsicSizeAlongMainAxis.contains(&child)) { 1310 if (isHorizontalWritingMode() == child.isHorizontalWritingMode()) 1311 child.setOverridingContainingBlockContentLogicalHeight(WTF::nullopt); 1312 else 1313 child.setOverridingContainingBlockContentLogicalWidth(WTF::nullopt); 1314 child.clearOverridingContentSize(); 1315 child.setChildNeedsLayout(MarkOnlyThis); 1316 child.layoutIfNeeded(); 1317 cacheChildMainSize(child); 1318 child.clearOverridingContainingBlockContentSize(); 1319 } 1320 } 1321 1322 LayoutUnit borderAndPadding = isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent(); 1323 LayoutUnit childInnerFlexBaseSize = computeInnerFlexBaseSizeForChild(child, borderAndPadding); 1324 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childInnerFlexBaseSize); 1325 LayoutUnit margin = isHorizontalFlow() ? child.horizontalMarginExtent() : child.verticalMarginExtent(); 1326 return FlexItem(child, childInnerFlexBaseSize, childMinMaxAppliedMainAxisExtent, borderAndPadding, margin); 1278 Vector<FlexItem> RenderFlexibleBox::constructFlexItems(bool relayoutChildren) 1279 { 1280 SetForScope<bool> inFlexItemConstruction(m_inFlexItemConstruction, true); 1281 1282 Vector<FlexItem> flexItems; 1283 for (auto* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { 1284 if (m_orderIterator.shouldSkipChild(*child)) { 1285 // Out-of-flow children are not flex items, so we skip them here. 1286 if (child->isOutOfFlowPositioned()) 1287 prepareChildForPositionedLayout(*child); 1288 continue; 1289 } 1290 1291 auto constructFlexItemForChildBox = [&](auto& childBox) { 1292 childBox.clearOverridingContentSize(); 1293 if (childHasIntrinsicMainAxisSize(childBox)) { 1294 // If this condition is true, then computeMainAxisExtentForChild will call 1295 // child.intrinsicContentLogicalHeight() and child.scrollbarLogicalHeight(), 1296 // so if the child has intrinsic min/max/preferred size, run layout on it now to make sure 1297 // its logical height and scroll bars are up to date. 1298 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, childBox); 1299 // Don't resolve percentages in children. This is especially important for the min-height calculation, 1300 // where we want percentages to be treated as auto. For flex-basis itself, this is not a problem because 1301 // by definition we have an indefinite flex basis here and thus percentages should not resolve. 1302 if (childBox.needsLayout() || !m_intrinsicSizeAlongMainAxis.contains(&childBox)) { 1303 if (isHorizontalWritingMode() == childBox.isHorizontalWritingMode()) 1304 childBox.setOverridingContainingBlockContentLogicalHeight(WTF::nullopt); 1305 else 1306 childBox.setOverridingContainingBlockContentLogicalWidth(WTF::nullopt); 1307 childBox.clearOverridingContentSize(); 1308 childBox.setChildNeedsLayout(MarkOnlyThis); 1309 childBox.layoutIfNeeded(); 1310 cacheChildMainSize(childBox); 1311 childBox.clearOverridingContainingBlockContentSize(); 1312 } 1313 } 1314 1315 auto borderAndPadding = isHorizontalFlow() ? childBox.horizontalBorderAndPaddingExtent() : childBox.verticalBorderAndPaddingExtent(); 1316 auto childInnerFlexBaseSize = computeInnerFlexBaseSizeForChild(childBox, borderAndPadding); 1317 auto childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(childBox, childInnerFlexBaseSize); 1318 auto margin = isHorizontalFlow() ? childBox.horizontalMarginExtent() : childBox.verticalMarginExtent(); 1319 return FlexItem(childBox, childInnerFlexBaseSize, childMinMaxAppliedMainAxisExtent, borderAndPadding, margin); 1320 }; 1321 flexItems.append(constructFlexItemForChildBox(*child)); 1322 } 1323 return flexItems; 1327 1324 } 1328 1325 -
trunk/Source/WebCore/rendering/RenderFlexibleBox.h
r276835 r277222 176 176 LayoutUnit adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize); 177 177 LayoutUnit adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize); 178 FlexItem constructFlexItem(RenderBox&,bool relayoutChildren);178 Vector<FlexItem> constructFlexItems(bool relayoutChildren); 179 179 180 180 void freezeInflexibleItems(FlexSign, Vector<FlexItem>& children, LayoutUnit& remainingFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink); … … 221 221 // This is SizeIsUnknown outside of layoutBlock() 222 222 SizeDefiniteness m_hasDefiniteHeight { SizeDefiniteness::Unknown }; 223 bool m_in Layout{ false };223 bool m_inFlexItemConstruction { false }; 224 224 bool m_shouldResetChildLogicalHeightBeforeLayout { false }; 225 225 };
Note: See TracChangeset
for help on using the changeset viewer.