Changeset 241869 in webkit
- Timestamp:
- Feb 21, 2019 9:58:15 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r241864 r241869 1 2019-02-21 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][Floats] Add support for placing formatting roots in-between floats. 4 https://bugs.webkit.org/show_bug.cgi?id=194902 5 6 Reviewed by Antti Koivisto. 7 8 * fast/block/block-only/floats-and-block-formatting-roots-expected.html: Added. 9 * fast/block/block-only/floats-and-block-formatting-roots.html: Added. 10 1 11 2019-02-21 Diego Pino Garcia <dpino@igalia.com> 2 12 -
trunk/Source/WebCore/ChangeLog
r241863 r241869 1 2019-02-21 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][Floats] Add support for placing formatting roots in-between floats. 4 https://bugs.webkit.org/show_bug.cgi?id=194902 5 6 Reviewed by Antti Koivisto. 7 8 This patch add support for placing a formatting root box in-between existing floats. 9 The initial vertical position of a formatting root is its static position which can make the box 10 placed above exsiting floats (whereas we can never place a regular float above existing floats.) 11 12 Test: fast/block/block-only/floats-and-block-formatting-roots.html 13 14 * layout/blockformatting/BlockFormattingContext.cpp: 15 (WebCore::Layout::BlockFormattingContext::computePositionToAvoidFloats const): 16 * layout/floats/FloatingContext.cpp: 17 (WebCore::Layout::FloatPair::LeftRightIndex::isEmpty const): 18 (WebCore::Layout::FloatPair::isEmpty const): 19 (WebCore::Layout::FloatPair::operator* const): 20 (WebCore::Layout::Iterator::operator* const): 21 (WebCore::Layout::begin): 22 (WebCore::Layout::end): 23 (WebCore::Layout::FloatingContext::positionForFloat const): 24 (WebCore::Layout::FloatingContext::positionForFormattingContextRoot const): 25 (WebCore::Layout::findAvailablePosition): 26 (WebCore::Layout::FloatingContext::findPositionForFloatBox const): 27 (WebCore::Layout::FloatingContext::findPositionForFormattingContextRoot const): 28 (WebCore::Layout::FloatPair::FloatPair): 29 (WebCore::Layout::FloatPair::left const): 30 (WebCore::Layout::FloatPair::right const): 31 (WebCore::Layout::FloatPair::intersects const): 32 (WebCore::Layout::FloatPair::operator == const): 33 (WebCore::Layout::FloatPair::horizontalConstraints const): 34 (WebCore::Layout::FloatPair::bottom const): 35 (WebCore::Layout::Iterator::operator++): 36 (WebCore::Layout::Iterator::set): 37 (WebCore::Layout::FloatingPair::isEmpty const): Deleted. 38 (WebCore::Layout::FloatingPair::verticalConstraint const): Deleted. 39 (WebCore::Layout::FloatingContext::positionForFloatAvoiding const): Deleted. 40 (WebCore::Layout::FloatingContext::floatingPosition const): Deleted. 41 (WebCore::Layout::FloatingPair::FloatingPair): Deleted. 42 (WebCore::Layout::FloatingPair::left const): Deleted. 43 (WebCore::Layout::FloatingPair::right const): Deleted. 44 (WebCore::Layout::FloatingPair::intersects const): Deleted. 45 (WebCore::Layout::FloatingPair::operator == const): Deleted. 46 (WebCore::Layout::FloatingPair::horizontalConstraints const): Deleted. 47 (WebCore::Layout::FloatingPair::bottom const): Deleted. 48 * layout/floats/FloatingContext.h: 49 1 50 2019-02-21 Rob Buis <rbuis@igalia.com> 2 51 -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp
r241264 r241869 292 292 return; 293 293 294 if (auto adjustedPosition = floatingContext.positionForF loatAvoiding(layoutBox))294 if (auto adjustedPosition = floatingContext.positionForFormattingContextRoot(layoutBox)) 295 295 layoutState.displayBoxForLayoutBox(layoutBox).setTopLeft(*adjustedPosition); 296 296 } -
trunk/Source/WebCore/layout/floats/FloatingContext.cpp
r241822 r241869 63 63 class Iterator; 64 64 65 class Float ingPair {65 class FloatPair { 66 66 public: 67 bool isEmpty() const { return !m_leftIndex && !m_rightIndex; } 67 struct LeftRightIndex { 68 bool isEmpty() const { return !left && !right;} 69 70 Optional<unsigned> left; 71 Optional<unsigned> right; 72 }; 73 74 bool isEmpty() const { return m_floatPair.isEmpty(); } 68 75 const FloatingState::FloatItem* left() const; 69 76 const FloatingState::FloatItem* right() const; … … 72 79 FloatAvoider::HorizontalConstraints horizontalConstraints() const; 73 80 PositionInContextRoot bottom() const; 74 bool operator==(const FloatingPair&) const; 81 LeftRightIndex operator*() const { return m_floatPair; }; 82 bool operator==(const FloatPair&) const; 75 83 76 84 private: 77 85 friend class Iterator; 78 Float ingPair(const FloatingState::FloatList&);86 FloatPair(const FloatingState::FloatList&); 79 87 80 88 const FloatingState::FloatList& m_floats; 81 82 Optional<unsigned> m_leftIndex; 83 Optional<unsigned> m_rightIndex; 89 LeftRightIndex m_floatPair; 84 90 PositionInContextRoot m_verticalPosition; 85 91 }; … … 89 95 Iterator(const FloatingState::FloatList&, Optional<PositionInContextRoot> verticalPosition); 90 96 91 const Float ingPair& operator*() const { return m_current; }97 const FloatPair& operator*() const { return m_current; } 92 98 Iterator& operator++(); 93 99 bool operator==(const Iterator&) const; … … 98 104 99 105 const FloatingState::FloatList& m_floats; 100 Float ingPair m_current;106 FloatPair m_current; 101 107 }; 102 108 103 static Iterator begin(const FloatingState & floatingState, PositionInContextRoot initialVerticalPosition)109 static Iterator begin(const FloatingState::FloatList& floats, PositionInContextRoot initialVerticalPosition) 104 110 { 105 111 // Start with the inner-most floating pair for the initial vertical position. 106 return Iterator(float ingState.floats(), initialVerticalPosition);107 } 108 109 static Iterator end(const FloatingState & floatingState)110 { 111 return Iterator(float ingState.floats(), WTF::nullopt);112 return Iterator(floats, initialVerticalPosition); 113 } 114 115 static Iterator end(const FloatingState::FloatList& floats) 116 { 117 return Iterator(floats, { }); 112 118 } 113 119 … … 173 179 // Find the top most position where the float box fits. 174 180 FloatBox floatBox = { layoutBox, m_floatingState, layoutState() }; 175 f loatingPosition(floatBox);181 findPositionForFloatBox(floatBox); 176 182 return floatBox.rectInContainingBlock().topLeft(); 177 183 } 178 184 179 Optional<Point> FloatingContext::positionForF loatAvoiding(const Box& layoutBox) const185 Optional<Point> FloatingContext::positionForFormattingContextRoot(const Box& layoutBox) const 180 186 { 181 187 ASSERT(layoutBox.establishesBlockFormattingContext()); … … 188 194 189 195 FloatAvoider floatAvoider = { layoutBox, m_floatingState, layoutState() }; 190 f loatingPosition(floatAvoider);196 findPositionForFormattingContextRoot(floatAvoider); 191 197 return { floatAvoider.rectInContainingBlock().topLeft() }; 192 198 } … … 260 266 } 261 267 262 void FloatingContext::floatingPosition(FloatAvoider& floatAvoider) const 268 static FloatPair::LeftRightIndex findAvailablePosition(FloatAvoider& floatAvoider, const FloatingState::FloatList& floats) 263 269 { 264 270 Optional<PositionInContextRoot> bottomMost; 265 auto end = Layout::end(m_floatingState); 266 for (auto iterator = begin(m_floatingState, { floatAvoider.rect().top() }); iterator != end; ++iterator) { 271 Optional<FloatPair::LeftRightIndex> innerMostLeftAndRight; 272 auto end = Layout::end(floats); 273 for (auto iterator = begin(floats, { floatAvoider.rect().top() }); iterator != end; ++iterator) { 267 274 ASSERT(!(*iterator).isEmpty()); 268 auto floats = *iterator; 275 auto leftRightFloatPair = *iterator; 276 innerMostLeftAndRight = innerMostLeftAndRight.valueOr(*leftRightFloatPair); 269 277 270 278 // Move the box horizontally so that it either 271 279 // 1. aligns with the current floating pair 272 280 // 2. or with the containing block's content box if there's no float to align with at this vertical position. 273 floatAvoider.setHorizontalConstraints( floats.horizontalConstraints());274 floatAvoider.setVerticalConstraint( floats.verticalConstraint());281 floatAvoider.setHorizontalConstraints(leftRightFloatPair.horizontalConstraints()); 282 floatAvoider.setVerticalConstraint(leftRightFloatPair.verticalConstraint()); 275 283 276 284 // Ensure that the float avoider … … 278 286 // containing block could push the candidate position beyond the current float horizontally (too far to the left/right) 279 287 // 2. avoids floats on both sides. 280 if (!floatAvoider.overflowsContainingBlock() && ! floats.intersects(floatAvoider.rect()))281 return ;282 283 bottomMost = floats.bottom();288 if (!floatAvoider.overflowsContainingBlock() && !leftRightFloatPair.intersects(floatAvoider.rect())) 289 return *innerMostLeftAndRight; 290 291 bottomMost = leftRightFloatPair.bottom(); 284 292 // Move to the next floating pair. 285 293 } … … 287 295 // The candidate box is already below of all the floats. 288 296 if (!bottomMost) 289 return ;297 return { }; 290 298 291 299 // Passed all the floats and still does not fit? Push it below the last float. 292 300 floatAvoider.setVerticalConstraint(*bottomMost); 293 301 floatAvoider.setHorizontalConstraints({ }); 294 } 295 296 FloatingPair::FloatingPair(const FloatingState::FloatList& floats) 302 ASSERT(innerMostLeftAndRight); 303 return *innerMostLeftAndRight; 304 } 305 306 void FloatingContext::findPositionForFloatBox(FloatBox& floatBox) const 307 { 308 findAvailablePosition(floatBox, m_floatingState.floats()); 309 } 310 311 void FloatingContext::findPositionForFormattingContextRoot(FloatAvoider& floatAvoider) const 312 { 313 // A non-floating formatting root's initial vertical position is its static position. 314 // It means that such boxes can end up vertically placed in-between existing floats (which is 315 // never the case for floats, since they cannot be placed above existing floats). 316 // ____ ____ 317 // | || F1 | 318 // | L1 | ---- 319 // | | ________ 320 // ---- | R1 | 321 // -------- 322 // Document order: 1. float: left (L1) 2. float: right (R1) 3. formatting root (F1) 323 // 324 // 1. Probe for available placement at initial position (note it runs a backward probing algorithm at a specific vertical position) 325 // 2. Check if there's any intersecing float below (forward seaching) 326 // 3. Align the box with the intersected float and probe for placement again (#1). 327 auto& floats = m_floatingState.floats(); 328 while (true) { 329 auto innerMostLeftAndRight = findAvailablePosition(floatAvoider, floats); 330 if (innerMostLeftAndRight.isEmpty()) 331 return; 332 333 auto overlappingFloatBox = [&floats](auto startFloatIndex, auto floatAvoiderRect) -> const FloatingState::FloatItem* { 334 for (auto i = startFloatIndex; i < floats.size(); ++i) { 335 auto& floatBox = floats[i]; 336 if (floatBox.rectWithMargin().intersects(floatAvoiderRect)) 337 return &floatBox; 338 } 339 return nullptr; 340 }; 341 342 auto startIndex = std::max(innerMostLeftAndRight.left.valueOr(0), innerMostLeftAndRight.right.valueOr(0)) + 1; 343 auto* intersectedFloatBox = overlappingFloatBox(startIndex, floatAvoider.rect()); 344 if (!intersectedFloatBox) 345 return; 346 floatAvoider.setVerticalConstraint({ intersectedFloatBox->rectWithMargin().top() }); 347 } 348 } 349 350 FloatPair::FloatPair(const FloatingState::FloatList& floats) 297 351 : m_floats(floats) 298 352 { 299 353 } 300 354 301 const FloatingState::FloatItem* Float ingPair::left() const302 { 303 if (!m_ leftIndex)355 const FloatingState::FloatItem* FloatPair::left() const 356 { 357 if (!m_floatPair.left) 304 358 return nullptr; 305 359 306 ASSERT(m_floats[*m_ leftIndex].isLeftPositioned());307 return &m_floats[*m_ leftIndex];308 } 309 310 const FloatingState::FloatItem* Float ingPair::right() const311 { 312 if (!m_ rightIndex)360 ASSERT(m_floats[*m_floatPair.left].isLeftPositioned()); 361 return &m_floats[*m_floatPair.left]; 362 } 363 364 const FloatingState::FloatItem* FloatPair::right() const 365 { 366 if (!m_floatPair.right) 313 367 return nullptr; 314 368 315 ASSERT(!m_floats[*m_ rightIndex].isLeftPositioned());316 return &m_floats[*m_ rightIndex];317 } 318 319 bool Float ingPair::intersects(const Display::Box::Rect& floatAvoiderRect) const369 ASSERT(!m_floats[*m_floatPair.right].isLeftPositioned()); 370 return &m_floats[*m_floatPair.right]; 371 } 372 373 bool FloatPair::intersects(const Display::Box::Rect& floatAvoiderRect) const 320 374 { 321 375 auto intersects = [&](auto* floating) { … … 323 377 }; 324 378 325 ASSERT( m_leftIndex || m_rightIndex);379 ASSERT(!m_floatPair.isEmpty()); 326 380 return intersects(left()) || intersects(right()); 327 381 } 328 382 329 bool Float ingPair::operator ==(const FloatingPair& other) const330 { 331 return m_ leftIndex == other.m_leftIndex && m_rightIndex == other.m_rightIndex;332 } 333 334 FloatAvoider::HorizontalConstraints Float ingPair::horizontalConstraints() const383 bool FloatPair::operator ==(const FloatPair& other) const 384 { 385 return m_floatPair.left == other.m_floatPair.left && m_floatPair.right == other.m_floatPair.right; 386 } 387 388 FloatAvoider::HorizontalConstraints FloatPair::horizontalConstraints() const 335 389 { 336 390 Optional<PositionInContextRoot> leftEdge; … … 346 400 } 347 401 348 PositionInContextRoot Float ingPair::bottom() const402 PositionInContextRoot FloatPair::bottom() const 349 403 { 350 404 auto* left = this->left(); … … 429 483 430 484 if (updateLeft) { 431 ASSERT(m_current.m_ leftIndex);485 ASSERT(m_current.m_floatPair.left); 432 486 m_current.m_verticalPosition = *leftBottom; 433 m_current.m_ leftIndex = findPreviousFloatingWithLowerBottom(Float::Left, *m_current.m_leftIndex);487 m_current.m_floatPair.left = findPreviousFloatingWithLowerBottom(Float::Left, *m_current.m_floatPair.left); 434 488 } 435 489 436 490 if (updateRight) { 437 ASSERT(m_current.m_ rightIndex);491 ASSERT(m_current.m_floatPair.right); 438 492 m_current.m_verticalPosition = *rightBottom; 439 m_current.m_ rightIndex = findPreviousFloatingWithLowerBottom(Float::Right, *m_current.m_rightIndex);493 m_current.m_floatPair.right = findPreviousFloatingWithLowerBottom(Float::Right, *m_current.m_floatPair.right); 440 494 } 441 495 … … 448 502 // 1. Check if the inner-most pair covers the vertical position. 449 503 // 2. Move outwards from the inner-most pair until the vertical postion intersects. 450 // (Note that verticalPosition has already been adjusted with the top of the last float.)451 452 504 m_current.m_verticalPosition = verticalPosition; 453 505 // No floats at all? 454 506 if (m_floats.isEmpty()) { 455 507 ASSERT_NOT_REACHED(); 456 457 m_current.m_leftIndex = { }; 458 m_current.m_rightIndex = { }; 508 m_current.m_floatPair = { }; 459 509 return; 460 510 } … … 464 514 ASSERT(!m_floats.isEmpty()); 465 515 466 auto index = floatingType == Float::Left ? m_current.m_ leftIndex : m_current.m_rightIndex;516 auto index = floatingType == Float::Left ? m_current.m_floatPair.left : m_current.m_floatPair.right; 467 517 // Start from the end if we don't have current yet. 468 518 index = index.valueOr(m_floats.size()); … … 472 522 return { }; 473 523 474 auto bottom = m_floats[*index].rectWithMargin().bottom();475 524 // Is this floating intrusive on this position? 476 if (bottom > verticalPosition) 525 auto rect = m_floats[*index].rectWithMargin(); 526 if (rect.top() <= verticalPosition && rect.bottom() > verticalPosition) 477 527 return index; 478 528 } … … 481 531 }; 482 532 483 m_current.m_ leftIndex= findFloatingBelow(Float::Left);484 m_current.m_ rightIndex= findFloatingBelow(Float::Right);485 486 ASSERT(!m_current.m_ leftIndex || (*m_current.m_leftIndex < m_floats.size() && m_floats[*m_current.m_leftIndex].isLeftPositioned()));487 ASSERT(!m_current.m_ rightIndex || (*m_current.m_rightIndex < m_floats.size() && !m_floats[*m_current.m_rightIndex].isLeftPositioned()));533 m_current.m_floatPair.left = findFloatingBelow(Float::Left); 534 m_current.m_floatPair.right = findFloatingBelow(Float::Right); 535 536 ASSERT(!m_current.m_floatPair.left || (*m_current.m_floatPair.left < m_floats.size() && m_floats[*m_current.m_floatPair.left].isLeftPositioned())); 537 ASSERT(!m_current.m_floatPair.right || (*m_current.m_floatPair.right < m_floats.size() && !m_floats[*m_current.m_floatPair.right].isLeftPositioned())); 488 538 } 489 539 -
trunk/Source/WebCore/layout/floats/FloatingContext.h
r240253 r241869 52 52 53 53 Point positionForFloat(const Box&) const; 54 Optional<Point> positionForF loatAvoiding(const Box&) const;54 Optional<Point> positionForFormattingContextRoot(const Box&) const; 55 55 56 56 struct ClearancePosition { … … 63 63 LayoutState& layoutState() const { return m_floatingState.layoutState(); } 64 64 65 void floatingPosition(FloatAvoider&) const; 65 void findPositionForFloatBox(FloatBox&) const; 66 void findPositionForFormattingContextRoot(FloatAvoider&) const; 66 67 67 68 FloatingState& m_floatingState; -
trunk/Tools/ChangeLog
r241866 r241869 1 2019-02-21 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][Floats] Add support for placing formatting roots in-between floats. 4 https://bugs.webkit.org/show_bug.cgi?id=194902 5 6 Reviewed by Antti Koivisto. 7 8 * LayoutReloaded/misc/LFC-passing-tests.txt: 9 1 10 2019-02-21 Adrian Perez de Castro <aperez@igalia.com> 2 11 -
trunk/Tools/LayoutReloaded/misc/LFC-passing-tests.txt
r241774 r241869 82 82 fast/block/block-only/floating-multiple-lefts.html 83 83 fast/block/block-only/floating-with-new-block-formatting-context.html 84 fast/block/block-only/floats-and-block-formatting-roots.html 84 85 fast/block/block-only/inflow-min-max-height.html 85 86 fast/block/block-only/inflow-min-max-width.html … … 844 845 css2.1/20110323/float-replaced-width-006.htm 845 846 css2.1/20110323/float-replaced-width-011.htm 846 css2.1/20110323/floats-wrap-top-below-bfc-002l.htm847 847 css2.1/20110323/floats-001.html 848 848 css2.1/20110323/floats-102.html 849 css2.1/20110323/floats-wrap-top-below-bfc-002l.htm 850 css2.1/20110323/floats-wrap-top-below-bfc-002r.htm 849 851 css2.1/20110323/inline-block-non-replaced-width-001.htm 850 852 css2.1/20110323/inline-block-non-replaced-width-002.htm
Note: See TracChangeset
for help on using the changeset viewer.