Changeset 246468 in webkit
- Timestamp:
- Jun 15, 2019, 12:30:06 PM (7 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
-
ChangeLog (modified) (1 diff)
-
layout/FormattingContext.cpp (modified) (2 diffs)
-
layout/FormattingContext.h (modified) (1 diff)
-
layout/blockformatting/BlockFormattingContext.cpp (modified) (6 diffs)
-
layout/blockformatting/BlockFormattingContext.h (modified) (3 diffs)
-
layout/blockformatting/BlockFormattingContextGeometry.cpp (modified) (2 diffs)
-
layout/floats/FloatingState.cpp (modified) (1 diff)
-
layout/layouttree/LayoutBlockContainer.cpp (modified) (1 diff)
-
layout/layouttree/LayoutBlockContainer.h (modified) (1 diff)
-
layout/layouttree/LayoutBox.cpp (modified) (1 diff)
-
layout/layouttree/LayoutBox.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r246467 r246468 1 2019-06-15 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][BFC] Fix available width for non-floating positioned float avoiders. 4 https://bugs.webkit.org/show_bug.cgi?id=198886 5 <rdar://problem/51773643> 6 7 Reviewed by Antti Koivisto. 8 9 Normally the available width for an in-flow block level box is the width of the containing block's content box. 10 However a non-floating positioned float avoider box might be constrained by existing floats. 11 The idea here is that we pre-compute(estimate) the vertical position and check the current floating context for 12 left and right floats. These floats contrain the available width and this computed value should be used instead of the containing block's 13 content box's width whe calculating the used width for width: auto. 14 15 * layout/FormattingContext.cpp: 16 (WebCore::Layout::mapHorizontalPositionToAncestor): 17 (WebCore::Layout::FormattingContext::mapLeftToAncestor): 18 (WebCore::Layout::FormattingContext::mapRightToAncestor): 19 (WebCore::Layout::FormattingContext::mapPointToAncestor): 20 (WebCore::Layout::FormattingContext::mapCoordinateToAncestor): Deleted. 21 * layout/FormattingContext.h: 22 * layout/blockformatting/BlockFormattingContext.cpp: 23 (WebCore::Layout::BlockFormattingContext::usedAvailableWidthForFloatAvoider const): 24 (WebCore::Layout::BlockFormattingContext::layoutFormattingContextRoot const): 25 (WebCore::Layout::BlockFormattingContext::computeStaticVerticalPosition const): 26 (WebCore::Layout::BlockFormattingContext::computeStaticHorizontalPosition const): 27 (WebCore::Layout::BlockFormattingContext::computeStaticPosition const): 28 (WebCore::Layout::BlockFormattingContext::computeEstimatedVerticalPositionForFormattingRoot const): 29 (WebCore::Layout::BlockFormattingContext::computeWidthAndMargin const): 30 * layout/blockformatting/BlockFormattingContext.h: 31 (WebCore::Layout::BlockFormattingContext::computeWidthAndMargin): 32 * layout/blockformatting/BlockFormattingContextGeometry.cpp: 33 (WebCore::Layout::BlockFormattingContext::Geometry::staticVerticalPosition): 34 (WebCore::Layout::BlockFormattingContext::Geometry::staticHorizontalPosition): 35 (WebCore::Layout::BlockFormattingContext::Geometry::staticPosition): 36 * layout/floats/FloatingState.cpp: 37 (WebCore::Layout::FloatingState::constraints const): 38 * layout/layouttree/LayoutBlockContainer.cpp: 39 (WebCore::Layout::BlockContainer::establishesInlineFormattingContextOnly const): 40 * layout/layouttree/LayoutBlockContainer.h: 41 * layout/layouttree/LayoutBox.cpp: 42 (WebCore::Layout::Box::isFloatAvoider const): 43 * layout/layouttree/LayoutBox.h: 44 (WebCore::Layout::Box::establishesInlineFormattingContextOnly const): 45 1 46 2019-06-15 Ludovico de Nittis <ludovico.denittis@collabora.com> 2 47 -
trunk/Source/WebCore/layout/FormattingContext.cpp
r241295 r246468 166 166 } 167 167 168 static LayoutUnit mapHorizontalPositionToAncestor(const LayoutState& layoutState, LayoutUnit horizontalPosition, const Container& containingBlock, const Container& ancestor) 169 { 170 // "horizontalPosition" is in the coordinate system of the "containingBlock". -> map from containingBlock to ancestor. 171 if (&containingBlock == &ancestor) 172 return horizontalPosition; 173 ASSERT(containingBlock.isDescendantOf(ancestor)); 174 for (auto* container = &containingBlock; container && container != &ancestor; container = container->containingBlock()) 175 horizontalPosition += layoutState.displayBoxForLayoutBox(*container).left(); 176 return horizontalPosition; 177 } 178 179 // FIXME: turn these into templates. 180 LayoutUnit FormattingContext::mapLeftToAncestor(const LayoutState& layoutState, const Box& layoutBox, const Container& ancestor) 181 { 182 ASSERT(layoutBox.containingBlock()); 183 return mapHorizontalPositionToAncestor(layoutState, layoutState.displayBoxForLayoutBox(layoutBox).left(), *layoutBox.containingBlock(), ancestor); 184 } 185 186 LayoutUnit FormattingContext::mapRightToAncestor(const LayoutState& layoutState, const Box& layoutBox, const Container& ancestor) 187 { 188 ASSERT(layoutBox.containingBlock()); 189 return mapHorizontalPositionToAncestor(layoutState, layoutState.displayBoxForLayoutBox(layoutBox).right(), *layoutBox.containingBlock(), ancestor); 190 } 191 168 192 Display::Box FormattingContext::mapBoxToAncestor(const LayoutState& layoutState, const Box& layoutBox, const Container& ancestor) 169 193 { … … 197 221 } 198 222 199 Point FormattingContext::map CoordinateToAncestor(const LayoutState& layoutState, Point position, const Container& containingBlock, const Container& ancestor)223 Point FormattingContext::mapPointToAncestor(const LayoutState& layoutState, Point position, const Container& containingBlock, const Container& ancestor) 200 224 { 201 225 auto mappedPosition = position; -
trunk/Source/WebCore/layout/FormattingContext.h
r241545 r246468 61 61 static Display::Box mapBoxToAncestor(const LayoutState&, const Box&, const Container& ancestor); 62 62 static LayoutUnit mapTopToAncestor(const LayoutState&, const Box&, const Container& ancestor); 63 static Point mapCoordinateToAncestor(const LayoutState&, Point, const Container& containingBlock, const Container& ancestor); 63 static LayoutUnit mapLeftToAncestor(const LayoutState&, const Box&, const Container& ancestor); 64 static LayoutUnit mapRightToAncestor(const LayoutState&, const Box&, const Container& ancestor); 65 static Point mapPointToAncestor(const LayoutState&, Point, const Container& containingBlock, const Container& ancestor); 64 66 65 67 protected: -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp
r241869 r246468 119 119 } 120 120 121 Optional<LayoutUnit> BlockFormattingContext::usedAvailableWidthForFloatAvoider(const FloatingContext& floatingContext, const Box& layoutBox) const 122 { 123 // Normally the available width for an in-flow block level box is the width of the containing block's content box. 124 // However (and can't find it anywhere in the spec) non-floating positioned float avoider block level boxes are constrained by existing floats. 125 if (!layoutBox.isFloatAvoider() || layoutBox.isFloatingPositioned()) 126 return { }; 127 auto& floatingState = floatingContext.floatingState(); 128 if (floatingState.isEmpty()) 129 return { }; 130 // Vertical static position is not computed yet, so let's just estimate it for now. 131 auto& formattingRoot = downcast<Container>(root()); 132 auto verticalPosition = FormattingContext::mapTopToAncestor(layoutState(), layoutBox, formattingRoot); 133 auto constraints = floatingState.constraints({ verticalPosition }, formattingRoot); 134 if (!constraints.left && !constraints.right) 135 return { }; 136 auto& containingBlock = downcast<Container>(*layoutBox.containingBlock()); 137 auto& containingBlockDisplayBox = layoutState().displayBoxForLayoutBox(containingBlock); 138 auto availableWidth = containingBlockDisplayBox.contentBoxWidth(); 139 140 LayoutUnit containingBlockLeft; 141 LayoutUnit containingBlockRight = containingBlockDisplayBox.right(); 142 if (&containingBlock != &formattingRoot) { 143 // Move containing block left/right to the root's coordinate system. 144 containingBlockLeft = FormattingContext::mapLeftToAncestor(layoutState(), containingBlock, formattingRoot); 145 containingBlockRight = FormattingContext::mapRightToAncestor(layoutState(), containingBlock, formattingRoot); 146 } 147 auto containingBlockContentBoxLeft = containingBlockLeft + containingBlockDisplayBox.borderLeft() + containingBlockDisplayBox.paddingLeft().valueOr(0); 148 auto containingBlockContentBoxRight = containingBlockRight - containingBlockDisplayBox.borderRight() + containingBlockDisplayBox.paddingRight().valueOr(0); 149 150 // Shrink the available space if the floats are actually intruding at this vertical position. 151 availableWidth -= (std::max<LayoutUnit>(0, constraints.left.valueOr(PositionInContextRoot { 0 }) - containingBlockContentBoxLeft) 152 + std::max<LayoutUnit>(0, containingBlockContentBoxRight - constraints.right.valueOr(PositionInContextRoot { containingBlockContentBoxRight }))); 153 return availableWidth; 154 } 155 121 156 void BlockFormattingContext::layoutFormattingContextRoot(FloatingContext& floatingContext, const Box& layoutBox) const 122 157 { 158 ASSERT(layoutBox.establishesFormattingContext()); 123 159 // Start laying out this formatting root in the formatting contenxt it lives in. 124 160 LOG_WITH_STREAM(FormattingContextLayout, stream << "[Compute] -> [Position][Border][Padding][Width][Margin] -> for layoutBox(" << &layoutBox << ")"); 125 161 computeBorderAndPadding(layoutBox); 126 computeWidthAndMargin(layoutBox); 127 computeStaticPosition(floatingContext, layoutBox); 162 computeStaticVerticalPosition(floatingContext, layoutBox); 163 164 computeWidthAndMargin(layoutBox, usedAvailableWidthForFloatAvoider(floatingContext, layoutBox)); 165 computeStaticHorizontalPosition(layoutBox); 128 166 // Swich over to the new formatting context (the one that the root creates). 129 167 auto formattingContext = layoutState().createFormattingContext(layoutBox); … … 173 211 } 174 212 175 void BlockFormattingContext::computeStatic Position(const FloatingContext& floatingContext, const Box& layoutBox) const176 { 177 auto& layoutState = this->layoutState(); 178 layoutState.displayBoxForLayoutBox(layoutBox).setTop Left(Geometry::staticPosition(layoutState, layoutBox));213 void BlockFormattingContext::computeStaticVerticalPosition(const FloatingContext& floatingContext, const Box& layoutBox) const 214 { 215 auto& layoutState = this->layoutState(); 216 layoutState.displayBoxForLayoutBox(layoutBox).setTop(Geometry::staticVerticalPosition(layoutState, layoutBox)); 179 217 if (layoutBox.hasFloatClear()) 180 218 computeEstimatedVerticalPositionForFloatClear(floatingContext, layoutBox); 181 219 else if (layoutBox.establishesFormattingContext()) 182 220 computeEstimatedVerticalPositionForFormattingRoot(layoutBox); 221 } 222 223 void BlockFormattingContext::computeStaticHorizontalPosition(const Box& layoutBox) const 224 { 225 layoutState().displayBoxForLayoutBox(layoutBox).setLeft(Geometry::staticHorizontalPosition(layoutState(), layoutBox)); 226 } 227 228 void BlockFormattingContext::computeStaticPosition(const FloatingContext& floatingContext, const Box& layoutBox) const 229 { 230 computeStaticVerticalPosition(floatingContext, layoutBox); 231 computeStaticHorizontalPosition(layoutBox); 183 232 } 184 233 … … 227 276 ASSERT(!layoutBox.hasFloatClear()); 228 277 229 auto avoidsFloats = layoutBox.isFloatingPositioned() || layoutBox.establishesBlockFormattingContext(); 230 if (avoidsFloats) 278 if (layoutBox.isFloatingPositioned()) { 231 279 computeEstimatedVerticalPositionForAncestors(layoutBox); 280 return; 281 } 282 283 computeEstimatedVerticalPosition(layoutBox); 284 computeEstimatedVerticalPositionForAncestors(layoutBox); 232 285 233 286 // If the inline formatting root is also the root for the floats (happens when the root box also establishes a block formatting context) 234 287 // the floats are in the coordinate system of this root. No need to find the final vertical position. 235 auto inlineContextInheritsFloats = layoutBox.establishesInlineFormattingContext () && !layoutBox.establishesBlockFormattingContext();288 auto inlineContextInheritsFloats = layoutBox.establishesInlineFormattingContextOnly(); 236 289 if (inlineContextInheritsFloats) { 237 290 computeEstimatedVerticalPosition(layoutBox); … … 296 349 } 297 350 298 void BlockFormattingContext::computeWidthAndMargin(const Box& layoutBox) const 299 { 300 auto& layoutState = this->layoutState(); 301 auto containingBlockWidth = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxWidth(); 351 void BlockFormattingContext::computeWidthAndMargin(const Box& layoutBox, Optional<LayoutUnit> usedAvailableWidth) const 352 { 353 auto& layoutState = this->layoutState(); 354 355 LayoutUnit availableWidth; 356 if (usedAvailableWidth) 357 availableWidth = *usedAvailableWidth; 358 else 359 availableWidth = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxWidth(); 302 360 303 361 auto compute = [&](Optional<LayoutUnit> usedWidth) -> WidthAndMargin { 304 auto usedValues = UsedHorizontalValues { containingBlockWidth, usedWidth, { } };362 auto usedValues = UsedHorizontalValues { availableWidth, usedWidth, { } }; 305 363 if (layoutBox.isInFlow()) 306 364 return Geometry::inFlowWidthAndMargin(layoutState, layoutBox, usedValues); … … 315 373 auto widthAndMargin = compute({ }); 316 374 317 if (auto maxWidth = Geometry::computedValueIfNotAuto(layoutBox.style().logicalMaxWidth(), containingBlockWidth)) {375 if (auto maxWidth = Geometry::computedValueIfNotAuto(layoutBox.style().logicalMaxWidth(), availableWidth)) { 318 376 auto maxWidthAndMargin = compute(maxWidth); 319 377 if (widthAndMargin.width > maxWidthAndMargin.width) … … 321 379 } 322 380 323 auto minWidth = Geometry::computedValueIfNotAuto(layoutBox.style().logicalMinWidth(), containingBlockWidth).valueOr(0);381 auto minWidth = Geometry::computedValueIfNotAuto(layoutBox.style().logicalMinWidth(), availableWidth).valueOr(0); 324 382 auto minWidthAndMargin = compute(minWidth); 325 383 if (widthAndMargin.width < minWidthAndMargin.width) -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h
r241263 r246468 56 56 void placeInFlowPositionedChildren(const Box&) const; 57 57 58 void computeWidthAndMargin(const Box& ) const;58 void computeWidthAndMargin(const Box&, Optional<LayoutUnit> usedAvailableWidth = { }) const; 59 59 void computeHeightAndMargin(const Box&) const; 60 60 61 void computeStaticHorizontalPosition(const Box&) const; 62 void computeStaticVerticalPosition(const FloatingContext&, const Box&) const; 61 63 void computeStaticPosition(const FloatingContext&, const Box&) const; 62 64 void computeFloatingPosition(const FloatingContext&, const Box&) const; … … 78 80 79 81 static Point staticPosition(const LayoutState&, const Box&); 82 static LayoutUnit staticVerticalPosition(const LayoutState&, const Box&); 83 static LayoutUnit staticHorizontalPosition(const LayoutState&, const Box&); 80 84 81 85 static bool intrinsicWidthConstraintsNeedChildrenWidth(const Box&); … … 132 136 void removeEstimatedMarginBefore(const Box& layoutBox) const { m_estimatedMarginBeforeList.remove(&layoutBox); } 133 137 bool hasEstimatedMarginBefore(const Box&) const; 138 Optional<LayoutUnit> usedAvailableWidthForFloatAvoider(const FloatingContext&, const Box&) const; 134 139 #ifndef NDEBUG 135 140 EstimatedMarginBefore estimatedMarginBefore(const Box& layoutBox) const { return m_estimatedMarginBeforeList.get(&layoutBox); } -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp
r245776 r246468 223 223 } 224 224 225 Point BlockFormattingContext::Geometry::staticPosition(const LayoutState& layoutState, const Box& layoutBox)225 LayoutUnit BlockFormattingContext::Geometry::staticVerticalPosition(const LayoutState& layoutState, const Box& layoutBox) 226 226 { 227 227 // https://www.w3.org/TR/CSS22/visuren.html#block-formatting … … 229 229 // The vertical distance between two sibling boxes is determined by the 'margin' properties. 230 230 // Vertical margins between adjacent block-level boxes in a block formatting context collapse. 231 // In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch).232 233 LayoutUnit top;234 auto& containingBlockDisplayBox = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock());235 231 if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling()) { 236 232 auto& previousInFlowDisplayBox = layoutState.displayBoxForLayoutBox(*previousInFlowSibling); 237 top = previousInFlowDisplayBox.bottom() + previousInFlowDisplayBox.marginAfter(); 238 } else 239 top = containingBlockDisplayBox.contentBoxTop(); 240 241 auto left = containingBlockDisplayBox.contentBoxLeft() + layoutState.displayBoxForLayoutBox(layoutBox).marginStart(); 242 LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position] -> static -> top(" << top << "px) left(" << left << "px) layoutBox(" << &layoutBox << ")"); 243 return { left, top }; 233 return previousInFlowDisplayBox.bottom() + previousInFlowDisplayBox.marginAfter(); 234 } 235 return layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxTop(); 236 } 237 238 LayoutUnit BlockFormattingContext::Geometry::staticHorizontalPosition(const LayoutState& layoutState, const Box& layoutBox) 239 { 240 // https://www.w3.org/TR/CSS22/visuren.html#block-formatting 241 // In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). 242 return layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock()).contentBoxLeft() + layoutState.displayBoxForLayoutBox(layoutBox).marginStart(); 243 } 244 245 Point BlockFormattingContext::Geometry::staticPosition(const LayoutState& layoutState, const Box& layoutBox) 246 { 247 return { staticHorizontalPosition(layoutState, layoutBox), staticVerticalPosition(layoutState, layoutBox) }; 244 248 } 245 249 -
trunk/Source/WebCore/layout/floats/FloatingState.cpp
r240240 r246468 122 122 123 123 if (coordinateMappingIsRequired) 124 adjustedPosition = FormattingContext::map CoordinateToAncestor(m_layoutState, adjustedPosition, downcast<Container>(formattingContextRoot), downcast<Container>(root()));124 adjustedPosition = FormattingContext::mapPointToAncestor(m_layoutState, adjustedPosition, downcast<Container>(formattingContextRoot), downcast<Container>(root())); 125 125 126 126 Constraints constraints; -
trunk/Source/WebCore/layout/layouttree/LayoutBlockContainer.cpp
r239427 r246468 54 54 } 55 55 56 bool BlockContainer::establishesInlineFormattingContextOnly() const 57 { 58 return establishesInlineFormattingContext() && !establishesBlockFormattingContext(); 59 } 60 56 61 } 57 62 } -
trunk/Source/WebCore/layout/layouttree/LayoutBlockContainer.h
r239427 r246468 43 43 44 44 bool establishesInlineFormattingContext() const final; 45 45 bool establishesInlineFormattingContextOnly() const final; 46 46 }; 47 47 -
trunk/Source/WebCore/layout/layouttree/LayoutBox.cpp
r241591 r246468 135 135 } 136 136 137 bool Box::isFloatAvoider() const 138 { 139 return establishesBlockFormattingContext() || isFloatingPositioned(); 140 } 141 137 142 const Container* Box::containingBlock() const 138 143 { -
trunk/Source/WebCore/layout/layouttree/LayoutBox.h
r245776 r246468 79 79 bool establishesBlockFormattingContextOnly() const; 80 80 virtual bool establishesInlineFormattingContext() const { return false; } 81 virtual bool establishesInlineFormattingContextOnly() const { return false; } 81 82 82 83 bool isInFlow() const { return !isFloatingOrOutOfFlowPositioned(); } … … 92 93 bool isRightFloatingPositioned() const; 93 94 bool hasFloatClear() const; 95 bool isFloatAvoider() const; 94 96 95 97 bool isFloatingOrOutOfFlowPositioned() const { return isFloatingPositioned() || isOutOfFlowPositioned(); }
Note:
See TracChangeset
for help on using the changeset viewer.