Changeset 260342 in webkit
- Timestamp:
- Apr 19, 2020 11:34:07 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r260340 r260342 1 2020-04-19 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][TFC] Add column spanning support for flexible table width 4 https://bugs.webkit.org/show_bug.cgi?id=210713 5 6 Reviewed by Antti Koivisto. 7 8 * fast/layoutformattingcontext/table-flex-width-colspans-expected.txt: Added. 9 * fast/layoutformattingcontext/table-flex-width-colspans.html: Added. 10 1 11 2020-04-19 Emilio Cobos Álvarez <emilio@crisal.io> 2 12 -
trunk/Source/WebCore/ChangeLog
r260340 r260342 1 2020-04-19 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][TFC] Add column spanning support for flexible table width 4 https://bugs.webkit.org/show_bug.cgi?id=210713 5 6 Reviewed by Antti Koivisto. 7 8 Test: fast/layoutformattingcontext/table-flex-width-colspans.html 9 10 This patch slightly changes the extra space distribution logic by using either the minimum or 11 the maximum width as the base initial width for the columns. 12 13 * layout/tableformatting/TableFormattingContext.cpp: 14 (WebCore::Layout::TableFormattingContext::layoutInFlowContent): 15 (WebCore::Layout::TableFormattingContext::computeColumnWidths): 16 (WebCore::Layout::TableFormattingContext::computeAndDistributeExtraHorizontalSpace): Deleted. 17 * layout/tableformatting/TableFormattingContext.h: 18 1 19 2020-04-19 Emilio Cobos Álvarez <emilio@crisal.io> 2 20 -
trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp
r260337 r260342 340 340 auto tableWidthConstraints = *grid.widthConstraints(); 341 341 342 auto distributeExtraHorizontalSpace = [&] (auto horizontalSpaceToDistribute) { 343 auto& columnList = grid.columns().list(); 344 ASSERT(!columnList.isEmpty()); 345 346 // 1. Collect minimum widths driven by <td> across columns but ignore spanning cells first. 347 struct ColumnMinimumWidth { 342 enum class ColumnWidthBalancingBase { MinimumWidth, MaximumWidth }; 343 auto computeColumnWidths = [&] (auto columnWidthBalancingBase, auto extraHorizontalSpace) { 344 auto slotInitialWidth = [&] (auto& slot) { 345 return columnWidthBalancingBase == ColumnWidthBalancingBase::MinimumWidth ? slot.widthConstraints().minimum : slot.widthConstraints().maximum; 346 }; 347 // 1. Collect initial widths driven by <td> across columns but ignore spanning cells first. 348 struct ColumnInitialWidth { 348 349 float value { 0 }; 349 350 bool isFixed { false }; 350 351 }; 351 Vector<Optional<Column MinimumWidth>> columnMinimumWidths(columnList.size());352 Vector<Optional<ColumnInitialWidth>> columnInitialWidths(columns.size()); 352 353 Vector<SlotPosition> spanningCellPositionList; 353 354 for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) { 354 355 for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) { 355 356 auto& slot = *grid.slot({ columnIndex, rowIndex }); 357 if (slot.isColumnSpanned()) 358 continue; 356 359 if (slot.hasColumnSpan()) { 357 360 spanningCellPositionList.append({ columnIndex, rowIndex }); 358 361 continue; 359 362 } 360 if (slot.isColumnSpanned()) 361 continue; 362 if (!columnMinimumWidths[columnIndex]) 363 columnMinimumWidths[columnIndex] = ColumnMinimumWidth { }; 364 columnMinimumWidths[columnIndex]->value = std::max<float>(columnMinimumWidths[columnIndex]->value, slot.widthConstraints().minimum); 365 } 366 } 367 // 2. Adjust the <td> minimum widths with fixed column widths (<col> vs. <td>) and also manage all-fixed-width-column content. 363 if (!columnInitialWidths[columnIndex]) 364 columnInitialWidths[columnIndex] = ColumnInitialWidth { }; 365 columnInitialWidths[columnIndex]->value = std::max<float>(columnInitialWidths[columnIndex]->value, slotInitialWidth(slot)); 366 } 367 } 368 // 2. Adjust the <td> initial widths with fixed column widths (<col> vs. <td>) and also manage all-fixed-width-column content. 368 369 auto hasFixedColumnsOnly = columns.hasFixedColumnsOnly(); 369 for (size_t columnIndex = 0; columnIndex < column List.size(); ++columnIndex) {370 auto& column = column List[columnIndex];370 for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) { 371 auto& column = columns.list()[columnIndex]; 371 372 if (!column.isFixedWidth()) 372 373 continue; … … 375 376 if (!columnFixedWidth) 376 377 continue; 377 if (!column MinimumWidths[columnIndex])378 column MinimumWidths[columnIndex] = ColumnMinimumWidth { };379 column MinimumWidths[columnIndex]->value = std::max(columnMinimumWidths[columnIndex]->value, columnFixedWidth.valueOr(0).toFloat());378 if (!columnInitialWidths[columnIndex]) 379 columnInitialWidths[columnIndex] = ColumnInitialWidth { }; 380 columnInitialWidths[columnIndex]->value = std::max(columnInitialWidths[columnIndex]->value, columnFixedWidth.valueOr(0).toFloat()); 380 381 // Fixed columns flex when there are no other flexing columns. 381 column MinimumWidths[columnIndex]->isFixed = !hasFixedColumnsOnly;382 columnInitialWidths[columnIndex]->isFixed = !hasFixedColumnsOnly; 382 383 } 383 384 … … 389 390 return grid.slot(a)->cell().columnSpan() < grid.slot(b)->cell().columnSpan(); 390 391 }); 391 // 3. Distribute the spanning cells' mimimum widths across the columns using the non-spanning minimumwidths.392 // 3. Distribute the spanning cells' mimimum widths across the columns using the non-spanning initial widths. 392 393 // e.g. [ 1 ][ 5 ][ 1 ] 393 394 // [ 9 ][ 1 ] 394 // The minimumwidths are: [ 2 ][ 7 ][ 1 ]395 // The initial widths are: [ 2 ][ 7 ][ 1 ] 395 396 for (auto spanningCellPosition : spanningCellPositionList) { 396 397 auto& slot = *grid.slot(spanningCellPosition); 397 398 ASSERT(slot.hasColumnSpan()); 398 399 auto& cell = slot.cell(); 399 float spanning MinimumWidth = slot.widthConstraints().minimum;400 if (!column MinimumWidths[cell.startColumn()] || !columnMinimumWidths[cell.endColumn() - 1]) {400 float spanningInitialWidth = slotInitialWidth(slot); 401 if (!columnInitialWidths[cell.startColumn()] || !columnInitialWidths[cell.endColumn() - 1]) { 401 402 // <td colspan=4>#a</td><td>#b</td> 402 403 // <td colspan=2>#c</td><td colspan=3>#d</td> … … 407 408 auto unresolvedColumnNumber = cell.columnSpan(); 408 409 for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) { 409 if (!column MinimumWidths[columnIndex])410 if (!columnInitialWidths[columnIndex]) 410 411 continue; 411 412 ASSERT(unresolvedColumnNumber); 412 413 --unresolvedColumnNumber; 413 spanning MinimumWidth = std::max(0.0f, spanningMinimumWidth - columnMinimumWidths[columnIndex]->value);414 spanningInitialWidth = std::max(0.0f, spanningInitialWidth - columnInitialWidths[columnIndex]->value); 414 415 } 415 416 ASSERT(unresolvedColumnNumber); 416 417 for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) { 417 if (column MinimumWidths[columnIndex])418 if (columnInitialWidths[columnIndex]) 418 419 continue; 419 column MinimumWidths[columnIndex] = ColumnMinimumWidth { spanningMinimumWidth / unresolvedColumnNumber, false };420 columnInitialWidths[columnIndex] = ColumnInitialWidth { spanningInitialWidth / unresolvedColumnNumber, false }; 420 421 } 421 422 } else { 422 // 1. Collect the non-spaning minimumwidths.423 float currentSpanning MinimumWidth = 0;423 // 1. Collect the non-spaning initial widths. 424 float currentSpanningInitialWidth = 0; 424 425 for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) 425 currentSpanning MinimumWidth += columnMinimumWidths[columnIndex]->value;426 if (currentSpanning MinimumWidth >= spanningMinimumWidth) {426 currentSpanningInitialWidth += columnInitialWidths[columnIndex]->value; 427 if (currentSpanningInitialWidth >= spanningInitialWidth) { 427 428 // The spanning cell fits the spanned columns just fine. Nothing to distribute. 428 429 continue; 429 430 } 430 // 2. Distribute the extra minimum width among the spanned columns based on the minimum colmn width.431 // e.g. spanning mimimum width: [ 9 ]. Current minimumwidths for the spanned columns: [ 1 ] [ 2 ]432 // New minimumwidths: [ 3 ] [ 6 ].433 auto spaceToDistribute = std::max(0.0f, spanning MinimumWidth - (cell.columnSpan() - 1) * grid.horizontalSpacing() - currentSpanningMinimumWidth);431 // 2. Distribute the extra width among the spanned columns based on the initial column width. 432 // e.g. spanning initial width: [ 9 ]. Current initial widths for the spanned columns: [ 1 ] [ 2 ] 433 // New initial widths: [ 3 ] [ 6 ]. 434 auto spaceToDistribute = std::max(0.0f, spanningInitialWidth - (cell.columnSpan() - 1) * grid.horizontalSpacing() - currentSpanningInitialWidth); 434 435 if (spaceToDistribute) { 435 436 for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) 436 column MinimumWidths[columnIndex]->value += spaceToDistribute / currentSpanningMinimumWidth * columnMinimumWidths[columnIndex]->value;437 columnInitialWidths[columnIndex]->value += spaceToDistribute / currentSpanningInitialWidth * columnInitialWidths[columnIndex]->value; 437 438 } 438 439 } 439 440 } 440 // 3. Distribute the extra space using the final minimumwidths.441 // 4. Distribute the extra space using the final initial widths. 441 442 #if ASSERT_ENABLED 442 // We have to have all the columns resolved at this point with valid minimumwidths.443 for (auto& column MinimumWidth : columnMinimumWidths)444 ASSERT(column MinimumWidth);443 // We have to have all the columns resolved at this point with valid initial widths. 444 for (auto& columnInitialWidth : columnInitialWidths) 445 ASSERT(columnInitialWidth); 445 446 #endif 446 447 // Fixed width columns don't participate in available space distribution. 447 448 // Unless there are no flexing column at all, then they start flexing as if they were not fixed at all. 448 449 float adjustabledHorizontalSpace = 0; 449 for (auto& columnMinimumWidth : columnMinimumWidths) { 450 if (columnMinimumWidth->isFixed) 451 continue; 452 adjustabledHorizontalSpace += columnMinimumWidth->value; 453 } 454 if (!adjustabledHorizontalSpace) 455 return; 456 // FIXME: Implement overconstrained columns when fixed width content is wider than the table. 450 for (auto& columnInitialWidth : columnInitialWidths) { 451 if (columnInitialWidth->isFixed) 452 continue; 453 adjustabledHorizontalSpace += columnInitialWidth->value; 454 } 455 457 456 for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) { 458 457 auto& column = columns.list()[columnIndex]; 459 auto minimumWidth = columnMinimumWidths[columnIndex]->value; 460 if (columnMinimumWidths[columnIndex]->isFixed) { 461 column.setLogicalWidth(LayoutUnit { minimumWidth }); 462 continue; 463 } 464 auto columnExtraSpace = horizontalSpaceToDistribute / adjustabledHorizontalSpace * minimumWidth; 465 column.setLogicalWidth(LayoutUnit { minimumWidth + columnExtraSpace }); 458 auto initialWidth = columnInitialWidths[columnIndex]->value; 459 460 if (!extraHorizontalSpace || columnInitialWidths[columnIndex]->isFixed) { 461 column.setLogicalWidth(LayoutUnit { initialWidth }); 462 continue; 463 } 464 auto columnExtraSpace = extraHorizontalSpace / adjustabledHorizontalSpace * initialWidth; 465 column.setLogicalWidth(LayoutUnit { initialWidth + columnExtraSpace }); 466 466 } 467 467 }; 468 468 469 enum class WidthConstraintsType { Minimum, Maximum }; 470 auto distributeMinOrMax = [&] (WidthConstraintsType type) { 471 for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) { 472 auto logicalWidth = LayoutUnit { }; 473 for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) { 474 auto widthConstraints = grid.slot({ columnIndex, rowIndex })->widthConstraints(); 475 logicalWidth = std::max(logicalWidth, type == WidthConstraintsType::Minimum ? widthConstraints.minimum : widthConstraints.maximum); 476 } 477 columns.list()[columnIndex].setLogicalWidth(logicalWidth); 478 } 479 }; 480 481 ASSERT(availableHorizontalSpace >= tableWidthConstraints.minimum); 482 if (availableHorizontalSpace == tableWidthConstraints.minimum) 483 distributeMinOrMax(WidthConstraintsType::Minimum); 484 else if (availableHorizontalSpace == tableWidthConstraints.maximum) 485 distributeMinOrMax(WidthConstraintsType::Maximum); 486 else 487 distributeExtraHorizontalSpace(availableHorizontalSpace - tableWidthConstraints.minimum); 469 auto needsExtraSpaceDistribution = availableHorizontalSpace != tableWidthConstraints.minimum && availableHorizontalSpace != tableWidthConstraints.maximum; 470 if (!needsExtraSpaceDistribution) { 471 auto columnWidthBalancingBase = availableHorizontalSpace == tableWidthConstraints.maximum ? ColumnWidthBalancingBase::MaximumWidth : ColumnWidthBalancingBase::MinimumWidth; 472 computeColumnWidths(columnWidthBalancingBase, LayoutUnit { }); 473 return; 474 } 475 auto horizontalSpaceToDistribute = availableHorizontalSpace - tableWidthConstraints.minimum; 476 ASSERT(horizontalSpaceToDistribute > 0); 477 computeColumnWidths(ColumnWidthBalancingBase::MinimumWidth, horizontalSpaceToDistribute); 488 478 } 489 479 -
trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h
r259982 r260342 68 68 void ensureTableGrid(); 69 69 IntrinsicWidthConstraints computedPreferredWidthForColumns(); 70 void computeAndDistributeExtraHorizontalSpace(LayoutUnit containingBlockWidth);70 void computeAndDistributeExtraHorizontalSpace(LayoutUnit availableHorizontalSpace); 71 71 72 72 void initializeDisplayBoxToBlank(Display::Box&) const;
Note: See TracChangeset
for help on using the changeset viewer.