1 /* 2 * Copyright (C) 1997 Martin Jones (mjones (at) kde.org) 3 * (C) 1997 Torben Weis (weis (at) kde.org) 4 * (C) 1998 Waldo Bastian (bastian (at) kde.org) 5 * (C) 1999 Lars Knoll (knoll (at) kde.org) 6 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 7 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. 8 * Copyright (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 */ 25 26 #include "config.h" 27 #include "core/rendering/RenderTable.h" 28 29 #include "core/HTMLNames.h" 30 #include "core/dom/Document.h" 31 #include "core/frame/FrameView.h" 32 #include "core/html/HTMLTableElement.h" 33 #include "core/paint/BoxPainter.h" 34 #include "core/paint/TablePainter.h" 35 #include "core/rendering/AutoTableLayout.h" 36 #include "core/rendering/FixedTableLayout.h" 37 #include "core/rendering/GraphicsContextAnnotator.h" 38 #include "core/rendering/HitTestResult.h" 39 #include "core/rendering/RenderLayer.h" 40 #include "core/rendering/RenderTableCaption.h" 41 #include "core/rendering/RenderTableCell.h" 42 #include "core/rendering/RenderTableCol.h" 43 #include "core/rendering/RenderTableSection.h" 44 #include "core/rendering/RenderView.h" 45 #include "core/rendering/SubtreeLayoutScope.h" 46 #include "core/rendering/TextAutosizer.h" 47 #include "core/rendering/style/StyleInheritedData.h" 48 #include "platform/graphics/GraphicsContextStateSaver.h" 49 50 namespace blink { 51 52 using namespace HTMLNames; 53 54 RenderTable::RenderTable(Element* element) 55 : RenderBlock(element) 56 , m_head(0) 57 , m_foot(0) 58 , m_firstBody(0) 59 , m_currentBorder(0) 60 , m_collapsedBordersValid(false) 61 , m_hasColElements(false) 62 , m_needsSectionRecalc(false) 63 , m_columnLogicalWidthChanged(false) 64 , m_columnRenderersValid(false) 65 , m_hasCellColspanThatDeterminesTableWidth(false) 66 , m_hSpacing(0) 67 , m_vSpacing(0) 68 , m_borderStart(0) 69 , m_borderEnd(0) 70 { 71 ASSERT(!childrenInline()); 72 m_columnPos.fill(0, 1); 73 } 74 75 RenderTable::~RenderTable() 76 { 77 } 78 79 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 80 { 81 RenderBlock::styleDidChange(diff, oldStyle); 82 propagateStyleToAnonymousChildren(); 83 84 bool oldFixedTableLayout = oldStyle ? oldStyle->isFixedTableLayout() : false; 85 86 // In the collapsed border model, there is no cell spacing. 87 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing(); 88 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing(); 89 m_columnPos[0] = m_hSpacing; 90 91 if (!m_tableLayout || style()->isFixedTableLayout() != oldFixedTableLayout) { 92 if (m_tableLayout) 93 m_tableLayout->willChangeTableLayout(); 94 95 // According to the CSS2 spec, you only use fixed table layout if an 96 // explicit width is specified on the table. Auto width implies auto table layout. 97 if (style()->isFixedTableLayout()) 98 m_tableLayout = adoptPtr(new FixedTableLayout(this)); 99 else 100 m_tableLayout = adoptPtr(new AutoTableLayout(this)); 101 } 102 103 // If border was changed, invalidate collapsed borders cache. 104 if (!needsLayout() && oldStyle && oldStyle->border() != style()->border()) 105 invalidateCollapsedBorders(); 106 } 107 108 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before) 109 { 110 if (!before || !ptr) 111 return; 112 RenderObject* o = before->previousSibling(); 113 while (o && o != ptr) 114 o = o->previousSibling(); 115 if (!o) 116 ptr = 0; 117 } 118 119 static inline bool needsTableSection(RenderObject* object) 120 { 121 // Return true if 'object' can't exist in an anonymous table without being 122 // wrapped in a table section box. 123 EDisplay display = object->style()->display(); 124 return display != TABLE_CAPTION && display != TABLE_COLUMN_GROUP && display != TABLE_COLUMN; 125 } 126 127 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) 128 { 129 bool wrapInAnonymousSection = !child->isOutOfFlowPositioned(); 130 131 if (child->isTableCaption()) 132 wrapInAnonymousSection = false; 133 else if (child->isRenderTableCol()) { 134 m_hasColElements = true; 135 wrapInAnonymousSection = false; 136 } else if (child->isTableSection()) { 137 switch (child->style()->display()) { 138 case TABLE_HEADER_GROUP: 139 resetSectionPointerIfNotBefore(m_head, beforeChild); 140 if (!m_head) { 141 m_head = toRenderTableSection(child); 142 } else { 143 resetSectionPointerIfNotBefore(m_firstBody, beforeChild); 144 if (!m_firstBody) 145 m_firstBody = toRenderTableSection(child); 146 } 147 wrapInAnonymousSection = false; 148 break; 149 case TABLE_FOOTER_GROUP: 150 resetSectionPointerIfNotBefore(m_foot, beforeChild); 151 if (!m_foot) { 152 m_foot = toRenderTableSection(child); 153 wrapInAnonymousSection = false; 154 break; 155 } 156 // Fall through. 157 case TABLE_ROW_GROUP: 158 resetSectionPointerIfNotBefore(m_firstBody, beforeChild); 159 if (!m_firstBody) 160 m_firstBody = toRenderTableSection(child); 161 wrapInAnonymousSection = false; 162 break; 163 default: 164 ASSERT_NOT_REACHED(); 165 } 166 } else 167 wrapInAnonymousSection = true; 168 169 if (child->isTableSection()) 170 setNeedsSectionRecalc(); 171 172 if (!wrapInAnonymousSection) { 173 if (beforeChild && beforeChild->parent() != this) 174 beforeChild = splitAnonymousBoxesAroundChild(beforeChild); 175 176 RenderBox::addChild(child, beforeChild); 177 return; 178 } 179 180 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) { 181 lastChild()->addChild(child); 182 return; 183 } 184 185 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) { 186 RenderObject* section = beforeChild->previousSibling(); 187 if (section && section->isTableSection() && section->isAnonymous()) { 188 section->addChild(child); 189 return; 190 } 191 } 192 193 RenderObject* lastBox = beforeChild; 194 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && needsTableSection(lastBox)) 195 lastBox = lastBox->parent(); 196 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) { 197 if (beforeChild == lastBox) 198 beforeChild = lastBox->slowFirstChild(); 199 lastBox->addChild(child, beforeChild); 200 return; 201 } 202 203 if (beforeChild && !beforeChild->isTableSection() && needsTableSection(beforeChild)) 204 beforeChild = 0; 205 206 RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this); 207 addChild(section, beforeChild); 208 section->addChild(child); 209 } 210 211 void RenderTable::addCaption(const RenderTableCaption* caption) 212 { 213 ASSERT(m_captions.find(caption) == kNotFound); 214 m_captions.append(const_cast<RenderTableCaption*>(caption)); 215 } 216 217 void RenderTable::removeCaption(const RenderTableCaption* oldCaption) 218 { 219 size_t index = m_captions.find(oldCaption); 220 ASSERT(index != kNotFound); 221 if (index == kNotFound) 222 return; 223 224 m_captions.remove(index); 225 } 226 227 void RenderTable::invalidateCachedColumns() 228 { 229 m_columnRenderersValid = false; 230 m_columnRenderers.resize(0); 231 } 232 233 void RenderTable::addColumn(const RenderTableCol*) 234 { 235 invalidateCachedColumns(); 236 } 237 238 void RenderTable::removeColumn(const RenderTableCol*) 239 { 240 invalidateCachedColumns(); 241 // We don't really need to recompute our sections, but we need to update our 242 // column count and whether we have a column. Currently, we only have one 243 // size-fit-all flag but we may have to consider splitting it. 244 setNeedsSectionRecalc(); 245 } 246 247 void RenderTable::updateLogicalWidth() 248 { 249 recalcSectionsIfNeeded(); 250 251 if (isOutOfFlowPositioned()) { 252 LogicalExtentComputedValues computedValues; 253 computePositionedLogicalWidth(computedValues); 254 setLogicalWidth(computedValues.m_extent); 255 setLogicalLeft(computedValues.m_position); 256 setMarginStart(computedValues.m_margins.m_start); 257 setMarginEnd(computedValues.m_margins.m_end); 258 } 259 260 RenderBlock* cb = containingBlock(); 261 262 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent() + (isOutOfFlowPositioned() ? cb->paddingLogicalWidth() : LayoutUnit(0)); 263 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode(); 264 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth; 265 266 Length styleLogicalWidth = style()->logicalWidth(); 267 if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic()) 268 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection)); 269 else { 270 // Subtract out any fixed margins from our available width for auto width tables. 271 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth); 272 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth); 273 LayoutUnit marginTotal = marginStart + marginEnd; 274 275 // Subtract out our margins to get the available content width. 276 LayoutUnit availableContentLogicalWidth = std::max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal); 277 if (shrinkToAvoidFloats() && cb->isRenderBlockFlow() && toRenderBlockFlow(cb)->containsFloats() && !hasPerpendicularContainingBlock) 278 availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb)); 279 280 // Ensure we aren't bigger than our available width. 281 setLogicalWidth(std::min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth())); 282 } 283 284 // Ensure we aren't bigger than our max-width style. 285 Length styleMaxLogicalWidth = style()->logicalMaxWidth(); 286 if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) { 287 LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth); 288 setLogicalWidth(std::min<int>(logicalWidth(), computedMaxLogicalWidth)); 289 } 290 291 // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as 292 // we ignore it if it means we wouldn't accomodate our content. 293 setLogicalWidth(std::max<int>(logicalWidth(), minPreferredLogicalWidth())); 294 295 // Ensure we aren't smaller than our min-width style. 296 Length styleMinLogicalWidth = style()->logicalMinWidth(); 297 if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) { 298 LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth); 299 setLogicalWidth(std::max<int>(logicalWidth(), computedMinLogicalWidth)); 300 } 301 302 // Finally, with our true width determined, compute our margins for real. 303 ComputedMarginValues marginValues; 304 computeMarginsForDirection(InlineDirection, cb, availableLogicalWidth, logicalWidth(), marginValues.m_start, marginValues.m_end, style()->marginStart(), style()->marginEnd()); 305 setMarginStart(marginValues.m_start); 306 setMarginEnd(marginValues.m_end); 307 308 // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate 309 // its own content which doesn't match CSS nor what authors expect. 310 // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion 311 // https://code.google.com/p/chromium/issues/detail?id=241198 312 ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt()); 313 } 314 315 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value. 316 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth) 317 { 318 if (styleLogicalWidth.isIntrinsic()) 319 return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection()); 320 321 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not. 322 LayoutUnit borders = 0; 323 bool isCSSTable = !isHTMLTableElement(node()); 324 if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX) 325 borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd()); 326 327 return minimumValueForLength(styleLogicalWidth, availableWidth) + borders; 328 } 329 330 LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight) 331 { 332 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore()); 333 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter()); 334 LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter; 335 LayoutUnit computedLogicalHeight = 0; 336 if (styleLogicalHeight.isFixed()) { 337 // HTML tables size as though CSS height includes border/padding, CSS tables do not. 338 LayoutUnit borders = LayoutUnit(); 339 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow. 340 if (isHTMLTableElement(node()) || style()->boxSizing() == BORDER_BOX) { 341 borders = borderAndPadding; 342 } 343 computedLogicalHeight = styleLogicalHeight.value() - borders; 344 } else if (styleLogicalHeight.isPercent()) 345 computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight); 346 else if (styleLogicalHeight.isIntrinsic()) 347 computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding); 348 else 349 ASSERT_NOT_REACHED(); 350 return std::max<LayoutUnit>(0, computedLogicalHeight); 351 } 352 353 void RenderTable::layoutCaption(RenderTableCaption* caption) 354 { 355 if (caption->needsLayout()) { 356 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption 357 // so that it does not mistakenly think any floats in the previous caption intrude into it. 358 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight())); 359 // If RenderTableCaption ever gets a layout() function, use it here. 360 caption->layoutIfNeeded(); 361 } 362 // Apply the margins to the location now that they are definitely available from layout 363 LayoutUnit captionLogicalTop = collapsedMarginBeforeForChild(caption) + logicalHeight(); 364 if (view()->layoutState()->isPaginated()) { 365 captionLogicalTop += caption->paginationStrut(); 366 caption->setPaginationStrut(0); 367 } 368 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), captionLogicalTop)); 369 370 if (!selfNeedsLayout()) 371 caption->setMayNeedPaintInvalidation(true); 372 373 setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption)); 374 } 375 376 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight) 377 { 378 if (extraLogicalHeight <= 0) 379 return; 380 381 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one. 382 if (RenderTableSection* section = firstBody()) 383 extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight); 384 385 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed. 386 // However our current distribution algorithm does not round properly and thus we can have some remaining height. 387 // ASSERT(!topSection() || !extraLogicalHeight); 388 } 389 390 void RenderTable::simplifiedNormalFlowLayout() 391 { 392 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) { 393 section->layoutIfNeeded(); 394 section->computeOverflowFromCells(); 395 } 396 } 397 398 void RenderTable::layout() 399 { 400 ASSERT(needsLayout()); 401 402 if (simplifiedLayout()) 403 return; 404 405 // Note: RenderTable is handled differently than other RenderBlocks and the LayoutScope 406 // must be created before the table begins laying out. 407 TextAutosizer::LayoutScope textAutosizerLayoutScope(this); 408 409 recalcSectionsIfNeeded(); 410 // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure 411 // to call this before we call borderStart/borderEnd to avoid getting a stale value. 412 recalcBordersInRowDirection(); 413 414 SubtreeLayoutScope layouter(*this); 415 416 // If any table section moved vertically, we will just issue paint invalidations for everything from that 417 // section down (it is quite unlikely that any of the following sections 418 // did not shift). 419 bool sectionMoved = false; 420 LayoutUnit movedSectionLogicalTop = 0; 421 { 422 LayoutState state(*this, locationOffset()); 423 424 setLogicalHeight(0); 425 426 LayoutUnit oldLogicalWidth = logicalWidth(); 427 updateLogicalWidth(); 428 429 if (logicalWidth() != oldLogicalWidth) { 430 for (unsigned i = 0; i < m_captions.size(); i++) 431 layouter.setNeedsLayout(m_captions[i]); 432 } 433 // FIXME: The optimisation below doesn't work since the internal table 434 // layout could have changed. We need to add a flag to the table 435 // layout that tells us if something has changed in the min max 436 // calculations to do it correctly. 437 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) 438 m_tableLayout->layout(); 439 440 LayoutUnit totalSectionLogicalHeight = 0; 441 LayoutUnit oldTableLogicalTop = 0; 442 for (unsigned i = 0; i < m_captions.size(); i++) 443 oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter(); 444 445 bool collapsing = collapseBorders(); 446 447 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 448 if (child->isTableSection()) { 449 RenderTableSection* section = toRenderTableSection(child); 450 if (m_columnLogicalWidthChanged) 451 layouter.setChildNeedsLayout(section); 452 section->layoutIfNeeded(); 453 totalSectionLogicalHeight += section->calcRowLogicalHeight(); 454 if (collapsing) 455 section->recalcOuterBorder(); 456 ASSERT(!section->needsLayout()); 457 } else if (child->isRenderTableCol()) { 458 child->layoutIfNeeded(); 459 ASSERT(!child->needsLayout()); 460 } else { 461 // FIXME: We should never have other type of children (they should be wrapped in an 462 // anonymous table section) but our code is too crazy and this can happen in practice. 463 // Until this is fixed, let's make sure we don't leave non laid out children in the tree. 464 child->layoutIfNeeded(); 465 } 466 } 467 468 // FIXME: Collapse caption margin. 469 if (!m_captions.isEmpty()) { 470 for (unsigned i = 0; i < m_captions.size(); i++) { 471 if (m_captions[i]->style()->captionSide() == CAPBOTTOM) 472 continue; 473 layoutCaption(m_captions[i]); 474 } 475 if (logicalHeight() != oldTableLogicalTop) { 476 sectionMoved = true; 477 movedSectionLogicalTop = std::min(logicalHeight(), oldTableLogicalTop); 478 } 479 } 480 481 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore()); 482 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter()); 483 484 setLogicalHeight(logicalHeight() + borderAndPaddingBefore); 485 486 LayoutUnit computedLogicalHeight = 0; 487 488 Length logicalHeightLength = style()->logicalHeight(); 489 if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive())) 490 computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength); 491 492 Length logicalMaxHeightLength = style()->logicalMaxHeight(); 493 if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) { 494 LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength); 495 computedLogicalHeight = std::min(computedLogicalHeight, computedMaxLogicalHeight); 496 } 497 498 Length logicalMinHeightLength = style()->logicalMinHeight(); 499 if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) { 500 LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength); 501 computedLogicalHeight = std::max(computedLogicalHeight, computedMinLogicalHeight); 502 } 503 504 distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight)); 505 506 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) 507 section->layoutRows(); 508 509 if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) { 510 // Completely empty tables (with no sections or anything) should at least honor specified height 511 // in strict mode. 512 setLogicalHeight(logicalHeight() + computedLogicalHeight); 513 } 514 515 LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd(); 516 if (!collapsing) 517 sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd(); 518 519 // position the table sections 520 RenderTableSection* section = topSection(); 521 while (section) { 522 if (!sectionMoved && section->logicalTop() != logicalHeight()) { 523 sectionMoved = true; 524 movedSectionLogicalTop = std::min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x()); 525 } 526 section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight())); 527 528 // As we may skip invalidation on the table, we need to ensure that sections are invalidated when they moved. 529 if (sectionMoved && !section->selfNeedsLayout()) 530 section->setMayNeedPaintInvalidation(true); 531 532 setLogicalHeight(logicalHeight() + section->logicalHeight()); 533 534 section = sectionBelow(section); 535 } 536 537 setLogicalHeight(logicalHeight() + borderAndPaddingAfter); 538 539 for (unsigned i = 0; i < m_captions.size(); i++) { 540 if (m_captions[i]->style()->captionSide() != CAPBOTTOM) 541 continue; 542 layoutCaption(m_captions[i]); 543 } 544 545 updateLogicalHeight(); 546 547 // table can be containing block of positioned elements. 548 // FIXME: Only pass true if width or height changed. 549 layoutPositionedObjects(true); 550 551 updateLayerTransformAfterLayout(); 552 553 // Layout was changed, so probably borders too. 554 invalidateCollapsedBorders(); 555 556 computeOverflow(clientLogicalBottom()); 557 } 558 559 // FIXME: This value isn't the intrinsic content logical height, but we need 560 // to update the value as its used by flexbox layout. crbug.com/367324 561 updateIntrinsicContentLogicalHeight(contentLogicalHeight()); 562 563 if (view()->layoutState()->pageLogicalHeight()) 564 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop())); 565 566 m_columnLogicalWidthChanged = false; 567 clearNeedsLayout(); 568 } 569 570 // Collect all the unique border values that we want to paint in a sorted list. 571 void RenderTable::recalcCollapsedBorders() 572 { 573 if (m_collapsedBordersValid) 574 return; 575 m_collapsedBordersValid = true; 576 m_collapsedBorders.clear(); 577 for (RenderObject* section = firstChild(); section; section = section->nextSibling()) { 578 if (!section->isTableSection()) 579 continue; 580 for (RenderTableRow* row = toRenderTableSection(section)->firstRow(); row; row = row->nextRow()) { 581 for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) { 582 ASSERT(cell->table() == this); 583 cell->collectBorderValues(m_collapsedBorders); 584 } 585 } 586 } 587 RenderTableCell::sortBorderValues(m_collapsedBorders); 588 } 589 590 void RenderTable::addOverflowFromChildren() 591 { 592 // Add overflow from borders. 593 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our 594 // descendant objects, but since tables don't support overflow:auto, this works out fine. 595 if (collapseBorders()) { 596 int rightBorderOverflow = width() + outerBorderRight() - borderRight(); 597 int leftBorderOverflow = borderLeft() - outerBorderLeft(); 598 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom(); 599 int topBorderOverflow = borderTop() - outerBorderTop(); 600 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow); 601 if (borderOverflowRect != pixelSnappedBorderBoxRect()) { 602 addLayoutOverflow(borderOverflowRect); 603 addVisualOverflow(borderOverflowRect); 604 } 605 } 606 607 // Add overflow from our caption. 608 for (unsigned i = 0; i < m_captions.size(); i++) 609 addOverflowFromChild(m_captions[i]); 610 611 // Add overflow from our sections. 612 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) 613 addOverflowFromChild(section); 614 } 615 616 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 617 { 618 TablePainter(*this).paint(paintInfo, paintOffset); 619 } 620 621 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 622 { 623 TablePainter(*this).paintObject(paintInfo, paintOffset); 624 } 625 626 void RenderTable::subtractCaptionRect(LayoutRect& rect) const 627 { 628 for (unsigned i = 0; i < m_captions.size(); i++) { 629 LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter(); 630 bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode(); 631 if (style()->isHorizontalWritingMode()) { 632 rect.setHeight(rect.height() - captionLogicalHeight); 633 if (captionIsBefore) 634 rect.move(0, captionLogicalHeight); 635 } else { 636 rect.setWidth(rect.width() - captionLogicalHeight); 637 if (captionIsBefore) 638 rect.move(captionLogicalHeight, 0); 639 } 640 } 641 } 642 643 void RenderTable::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 644 { 645 TablePainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); 646 } 647 648 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 649 { 650 TablePainter(*this).paintMask(paintInfo, paintOffset); 651 } 652 653 void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const 654 { 655 recalcSectionsIfNeeded(); 656 // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call. 657 // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility 658 // of reading out stale values. 659 const_cast<RenderTable*>(this)->recalcBordersInRowDirection(); 660 // FIXME: Restructure the table layout code so that we can make this method const. 661 const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth); 662 663 // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths. 664 } 665 666 void RenderTable::computePreferredLogicalWidths() 667 { 668 ASSERT(preferredLogicalWidthsDirty()); 669 670 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 671 672 int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection(); 673 m_minPreferredLogicalWidth += bordersPaddingAndSpacing; 674 m_maxPreferredLogicalWidth += bordersPaddingAndSpacing; 675 676 m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 677 678 for (unsigned i = 0; i < m_captions.size(); i++) 679 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth()); 680 681 RenderStyle* styleToUse = style(); 682 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width. 683 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) { 684 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); 685 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); 686 } 687 688 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth. 689 if (styleToUse->logicalMaxWidth().isFixed()) { 690 // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'. 691 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); 692 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 693 } 694 695 // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does, 696 // so a bunch of tests break doing this naively. 697 clearPreferredLogicalWidthsDirty(); 698 } 699 700 RenderTableSection* RenderTable::topNonEmptySection() const 701 { 702 RenderTableSection* section = topSection(); 703 if (section && !section->numRows()) 704 section = sectionBelow(section, SkipEmptySections); 705 return section; 706 } 707 708 void RenderTable::splitColumn(unsigned position, unsigned firstSpan) 709 { 710 // We split the column at "position", taking "firstSpan" cells from the span. 711 ASSERT(m_columns[position].span > firstSpan); 712 m_columns.insert(position, ColumnStruct(firstSpan)); 713 m_columns[position + 1].span -= firstSpan; 714 715 // Propagate the change in our columns representation to the sections that don't need 716 // cell recalc. If they do, they will be synced up directly with m_columns later. 717 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 718 if (!child->isTableSection()) 719 continue; 720 721 RenderTableSection* section = toRenderTableSection(child); 722 if (section->needsCellRecalc()) 723 continue; 724 725 section->splitColumn(position, firstSpan); 726 } 727 728 m_columnPos.grow(numEffCols() + 1); 729 } 730 731 void RenderTable::appendColumn(unsigned span) 732 { 733 unsigned newColumnIndex = m_columns.size(); 734 m_columns.append(ColumnStruct(span)); 735 736 // Unless the table has cell(s) with colspan that exceed the number of columns afforded 737 // by the other rows in the table we can use the fast path when mapping columns to effective columns. 738 m_hasCellColspanThatDeterminesTableWidth = m_hasCellColspanThatDeterminesTableWidth || span > 1; 739 740 // Propagate the change in our columns representation to the sections that don't need 741 // cell recalc. If they do, they will be synced up directly with m_columns later. 742 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 743 if (!child->isTableSection()) 744 continue; 745 746 RenderTableSection* section = toRenderTableSection(child); 747 if (section->needsCellRecalc()) 748 continue; 749 750 section->appendColumn(newColumnIndex); 751 } 752 753 m_columnPos.grow(numEffCols() + 1); 754 } 755 756 RenderTableCol* RenderTable::firstColumn() const 757 { 758 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 759 if (child->isRenderTableCol()) 760 return toRenderTableCol(child); 761 } 762 763 return 0; 764 } 765 766 void RenderTable::updateColumnCache() const 767 { 768 ASSERT(m_hasColElements); 769 ASSERT(m_columnRenderers.isEmpty()); 770 ASSERT(!m_columnRenderersValid); 771 772 for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) { 773 if (columnRenderer->isTableColumnGroupWithColumnChildren()) 774 continue; 775 m_columnRenderers.append(columnRenderer); 776 } 777 m_columnRenderersValid = true; 778 } 779 780 RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const 781 { 782 ASSERT(m_hasColElements); 783 784 if (!m_columnRenderersValid) 785 updateColumnCache(); 786 787 unsigned columnCount = 0; 788 for (unsigned i = 0; i < m_columnRenderers.size(); i++) { 789 RenderTableCol* columnRenderer = m_columnRenderers[i]; 790 unsigned span = columnRenderer->span(); 791 unsigned startCol = columnCount; 792 ASSERT(span >= 1); 793 unsigned endCol = columnCount + span - 1; 794 columnCount += span; 795 if (columnCount > col) { 796 if (startEdge) 797 *startEdge = startCol == col; 798 if (endEdge) 799 *endEdge = endCol == col; 800 return columnRenderer; 801 } 802 } 803 return 0; 804 } 805 806 void RenderTable::recalcSections() const 807 { 808 ASSERT(m_needsSectionRecalc); 809 810 m_head = 0; 811 m_foot = 0; 812 m_firstBody = 0; 813 m_hasColElements = false; 814 m_hasCellColspanThatDeterminesTableWidth = hasCellColspanThatDeterminesTableWidth(); 815 816 // We need to get valid pointers to caption, head, foot and first body again 817 RenderObject* nextSibling; 818 for (RenderObject* child = firstChild(); child; child = nextSibling) { 819 nextSibling = child->nextSibling(); 820 switch (child->style()->display()) { 821 case TABLE_COLUMN: 822 case TABLE_COLUMN_GROUP: 823 m_hasColElements = true; 824 break; 825 case TABLE_HEADER_GROUP: 826 if (child->isTableSection()) { 827 RenderTableSection* section = toRenderTableSection(child); 828 if (!m_head) 829 m_head = section; 830 else if (!m_firstBody) 831 m_firstBody = section; 832 section->recalcCellsIfNeeded(); 833 } 834 break; 835 case TABLE_FOOTER_GROUP: 836 if (child->isTableSection()) { 837 RenderTableSection* section = toRenderTableSection(child); 838 if (!m_foot) 839 m_foot = section; 840 else if (!m_firstBody) 841 m_firstBody = section; 842 section->recalcCellsIfNeeded(); 843 } 844 break; 845 case TABLE_ROW_GROUP: 846 if (child->isTableSection()) { 847 RenderTableSection* section = toRenderTableSection(child); 848 if (!m_firstBody) 849 m_firstBody = section; 850 section->recalcCellsIfNeeded(); 851 } 852 break; 853 default: 854 break; 855 } 856 } 857 858 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section) 859 unsigned maxCols = 0; 860 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 861 if (child->isTableSection()) { 862 RenderTableSection* section = toRenderTableSection(child); 863 unsigned sectionCols = section->numColumns(); 864 if (sectionCols > maxCols) 865 maxCols = sectionCols; 866 } 867 } 868 869 m_columns.resize(maxCols); 870 m_columnPos.resize(maxCols + 1); 871 872 ASSERT(selfNeedsLayout()); 873 874 m_needsSectionRecalc = false; 875 } 876 877 int RenderTable::calcBorderStart() const 878 { 879 if (!collapseBorders()) 880 return RenderBlock::borderStart(); 881 882 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2. 883 if (!numEffCols()) 884 return 0; 885 886 unsigned borderWidth = 0; 887 888 const BorderValue& tableStartBorder = style()->borderStart(); 889 if (tableStartBorder.style() == BHIDDEN) 890 return 0; 891 if (tableStartBorder.style() > BHIDDEN) 892 borderWidth = tableStartBorder.width(); 893 894 if (RenderTableCol* column = colElement(0)) { 895 // FIXME: We don't account for direction on columns and column groups. 896 const BorderValue& columnAdjoiningBorder = column->style()->borderStart(); 897 if (columnAdjoiningBorder.style() == BHIDDEN) 898 return 0; 899 if (columnAdjoiningBorder.style() > BHIDDEN) 900 borderWidth = std::max(borderWidth, columnAdjoiningBorder.width()); 901 // FIXME: This logic doesn't properly account for the first column in the first column-group case. 902 } 903 904 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) { 905 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart(); 906 if (sectionAdjoiningBorder.style() == BHIDDEN) 907 return 0; 908 909 if (sectionAdjoiningBorder.style() > BHIDDEN) 910 borderWidth = std::max(borderWidth, sectionAdjoiningBorder.width()); 911 912 if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) { 913 // FIXME: Make this work with perpendicular and flipped cells. 914 const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart(); 915 if (startCellAdjoiningBorder.style() == BHIDDEN) 916 return 0; 917 918 const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart(); 919 if (firstRowAdjoiningBorder.style() == BHIDDEN) 920 return 0; 921 922 if (startCellAdjoiningBorder.style() > BHIDDEN) 923 borderWidth = std::max(borderWidth, startCellAdjoiningBorder.width()); 924 if (firstRowAdjoiningBorder.style() > BHIDDEN) 925 borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width()); 926 } 927 } 928 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2; 929 } 930 931 int RenderTable::calcBorderEnd() const 932 { 933 if (!collapseBorders()) 934 return RenderBlock::borderEnd(); 935 936 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2. 937 if (!numEffCols()) 938 return 0; 939 940 unsigned borderWidth = 0; 941 942 const BorderValue& tableEndBorder = style()->borderEnd(); 943 if (tableEndBorder.style() == BHIDDEN) 944 return 0; 945 if (tableEndBorder.style() > BHIDDEN) 946 borderWidth = tableEndBorder.width(); 947 948 unsigned endColumn = numEffCols() - 1; 949 if (RenderTableCol* column = colElement(endColumn)) { 950 // FIXME: We don't account for direction on columns and column groups. 951 const BorderValue& columnAdjoiningBorder = column->style()->borderEnd(); 952 if (columnAdjoiningBorder.style() == BHIDDEN) 953 return 0; 954 if (columnAdjoiningBorder.style() > BHIDDEN) 955 borderWidth = std::max(borderWidth, columnAdjoiningBorder.width()); 956 // FIXME: This logic doesn't properly account for the last column in the last column-group case. 957 } 958 959 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) { 960 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd(); 961 if (sectionAdjoiningBorder.style() == BHIDDEN) 962 return 0; 963 964 if (sectionAdjoiningBorder.style() > BHIDDEN) 965 borderWidth = std::max(borderWidth, sectionAdjoiningBorder.width()); 966 967 if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) { 968 // FIXME: Make this work with perpendicular and flipped cells. 969 const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd(); 970 if (endCellAdjoiningBorder.style() == BHIDDEN) 971 return 0; 972 973 const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd(); 974 if (firstRowAdjoiningBorder.style() == BHIDDEN) 975 return 0; 976 977 if (endCellAdjoiningBorder.style() > BHIDDEN) 978 borderWidth = std::max(borderWidth, endCellAdjoiningBorder.width()); 979 if (firstRowAdjoiningBorder.style() > BHIDDEN) 980 borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width()); 981 } 982 } 983 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2; 984 } 985 986 void RenderTable::recalcBordersInRowDirection() 987 { 988 // FIXME: We need to compute the collapsed before / after borders in the same fashion. 989 m_borderStart = calcBorderStart(); 990 m_borderEnd = calcBorderEnd(); 991 } 992 993 int RenderTable::borderBefore() const 994 { 995 if (collapseBorders()) { 996 recalcSectionsIfNeeded(); 997 return outerBorderBefore(); 998 } 999 return RenderBlock::borderBefore(); 1000 } 1001 1002 int RenderTable::borderAfter() const 1003 { 1004 if (collapseBorders()) { 1005 recalcSectionsIfNeeded(); 1006 return outerBorderAfter(); 1007 } 1008 return RenderBlock::borderAfter(); 1009 } 1010 1011 int RenderTable::outerBorderBefore() const 1012 { 1013 if (!collapseBorders()) 1014 return 0; 1015 int borderWidth = 0; 1016 if (RenderTableSection* topSection = this->topSection()) { 1017 borderWidth = topSection->outerBorderBefore(); 1018 if (borderWidth < 0) 1019 return 0; // Overridden by hidden 1020 } 1021 const BorderValue& tb = style()->borderBefore(); 1022 if (tb.style() == BHIDDEN) 1023 return 0; 1024 if (tb.style() > BHIDDEN) 1025 borderWidth = std::max<int>(borderWidth, tb.width() / 2); 1026 return borderWidth; 1027 } 1028 1029 int RenderTable::outerBorderAfter() const 1030 { 1031 if (!collapseBorders()) 1032 return 0; 1033 int borderWidth = 0; 1034 1035 if (RenderTableSection* section = bottomSection()) { 1036 borderWidth = section->outerBorderAfter(); 1037 if (borderWidth < 0) 1038 return 0; // Overridden by hidden 1039 } 1040 const BorderValue& tb = style()->borderAfter(); 1041 if (tb.style() == BHIDDEN) 1042 return 0; 1043 if (tb.style() > BHIDDEN) 1044 borderWidth = std::max<int>(borderWidth, (tb.width() + 1) / 2); 1045 return borderWidth; 1046 } 1047 1048 int RenderTable::outerBorderStart() const 1049 { 1050 if (!collapseBorders()) 1051 return 0; 1052 1053 int borderWidth = 0; 1054 1055 const BorderValue& tb = style()->borderStart(); 1056 if (tb.style() == BHIDDEN) 1057 return 0; 1058 if (tb.style() > BHIDDEN) 1059 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2; 1060 1061 bool allHidden = true; 1062 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) { 1063 int sw = section->outerBorderStart(); 1064 if (sw < 0) 1065 continue; 1066 allHidden = false; 1067 borderWidth = std::max(borderWidth, sw); 1068 } 1069 if (allHidden) 1070 return 0; 1071 1072 return borderWidth; 1073 } 1074 1075 int RenderTable::outerBorderEnd() const 1076 { 1077 if (!collapseBorders()) 1078 return 0; 1079 1080 int borderWidth = 0; 1081 1082 const BorderValue& tb = style()->borderEnd(); 1083 if (tb.style() == BHIDDEN) 1084 return 0; 1085 if (tb.style() > BHIDDEN) 1086 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2; 1087 1088 bool allHidden = true; 1089 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) { 1090 int sw = section->outerBorderEnd(); 1091 if (sw < 0) 1092 continue; 1093 allHidden = false; 1094 borderWidth = std::max(borderWidth, sw); 1095 } 1096 if (allHidden) 1097 return 0; 1098 1099 return borderWidth; 1100 } 1101 1102 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const 1103 { 1104 recalcSectionsIfNeeded(); 1105 1106 if (section == m_head) 1107 return 0; 1108 1109 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling(); 1110 while (prevSection) { 1111 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows())) 1112 break; 1113 prevSection = prevSection->previousSibling(); 1114 } 1115 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows())) 1116 prevSection = m_head; 1117 return toRenderTableSection(prevSection); 1118 } 1119 1120 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const 1121 { 1122 recalcSectionsIfNeeded(); 1123 1124 if (section == m_foot) 1125 return 0; 1126 1127 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling(); 1128 while (nextSection) { 1129 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows())) 1130 break; 1131 nextSection = nextSection->nextSibling(); 1132 } 1133 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows())) 1134 nextSection = m_foot; 1135 return toRenderTableSection(nextSection); 1136 } 1137 1138 RenderTableSection* RenderTable::bottomSection() const 1139 { 1140 recalcSectionsIfNeeded(); 1141 1142 if (m_foot) 1143 return m_foot; 1144 1145 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 1146 if (child->isTableSection()) 1147 return toRenderTableSection(child); 1148 } 1149 1150 return 0; 1151 } 1152 1153 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const 1154 { 1155 recalcSectionsIfNeeded(); 1156 1157 // Find the section and row to look in 1158 unsigned r = cell->rowIndex(); 1159 RenderTableSection* section = 0; 1160 unsigned rAbove = 0; 1161 if (r > 0) { 1162 // cell is not in the first row, so use the above row in its own section 1163 section = cell->section(); 1164 rAbove = r - 1; 1165 } else { 1166 section = sectionAbove(cell->section(), SkipEmptySections); 1167 if (section) { 1168 ASSERT(section->numRows()); 1169 rAbove = section->numRows() - 1; 1170 } 1171 } 1172 1173 // Look up the cell in the section's grid, which requires effective col index 1174 if (section) { 1175 unsigned effCol = colToEffCol(cell->col()); 1176 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol); 1177 return aboveCell.primaryCell(); 1178 } else 1179 return 0; 1180 } 1181 1182 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const 1183 { 1184 recalcSectionsIfNeeded(); 1185 1186 // Find the section and row to look in 1187 unsigned r = cell->rowIndex() + cell->rowSpan() - 1; 1188 RenderTableSection* section = 0; 1189 unsigned rBelow = 0; 1190 if (r < cell->section()->numRows() - 1) { 1191 // The cell is not in the last row, so use the next row in the section. 1192 section = cell->section(); 1193 rBelow = r + 1; 1194 } else { 1195 section = sectionBelow(cell->section(), SkipEmptySections); 1196 if (section) 1197 rBelow = 0; 1198 } 1199 1200 // Look up the cell in the section's grid, which requires effective col index 1201 if (section) { 1202 unsigned effCol = colToEffCol(cell->col()); 1203 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol); 1204 return belowCell.primaryCell(); 1205 } else 1206 return 0; 1207 } 1208 1209 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const 1210 { 1211 recalcSectionsIfNeeded(); 1212 1213 RenderTableSection* section = cell->section(); 1214 unsigned effCol = colToEffCol(cell->col()); 1215 if (!effCol) 1216 return 0; 1217 1218 // If we hit a colspan back up to a real cell. 1219 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1); 1220 return prevCell.primaryCell(); 1221 } 1222 1223 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const 1224 { 1225 recalcSectionsIfNeeded(); 1226 1227 unsigned effCol = colToEffCol(cell->col() + cell->colSpan()); 1228 if (effCol >= numEffCols()) 1229 return 0; 1230 return cell->section()->primaryCellAt(cell->rowIndex(), effCol); 1231 } 1232 1233 int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const 1234 { 1235 ASSERT(linePositionMode == PositionOnContainingLine); 1236 int baseline = firstLineBoxBaseline(); 1237 if (baseline != -1) { 1238 if (isInline()) 1239 return beforeMarginInLineDirection(direction) + baseline; 1240 return baseline; 1241 } 1242 1243 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); 1244 } 1245 1246 int RenderTable::inlineBlockBaseline(LineDirectionMode) const 1247 { 1248 // Tables are skipped when computing an inline-block's baseline. 1249 return -1; 1250 } 1251 1252 int RenderTable::firstLineBoxBaseline() const 1253 { 1254 // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1 1255 // doesn't define the baseline of a 'table' only an 'inline-table'). 1256 // This is also needed to properly determine the baseline of a cell if it has a table child. 1257 1258 if (isWritingModeRoot()) 1259 return -1; 1260 1261 recalcSectionsIfNeeded(); 1262 1263 const RenderTableSection* topNonEmptySection = this->topNonEmptySection(); 1264 if (!topNonEmptySection) 1265 return -1; 1266 1267 int baseline = topNonEmptySection->firstLineBoxBaseline(); 1268 if (baseline > 0) 1269 return topNonEmptySection->logicalTop() + baseline; 1270 1271 // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value? 1272 return -1; 1273 } 1274 1275 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy) 1276 { 1277 LayoutRect rect = RenderBlock::overflowClipRect(location, relevancy); 1278 1279 // If we have a caption, expand the clip to include the caption. 1280 // FIXME: Technically this is wrong, but it's virtually impossible to fix this 1281 // for real until captions have been re-written. 1282 // FIXME: This code assumes (like all our other caption code) that only top/bottom are 1283 // supported. When we actually support left/right and stop mapping them to top/bottom, 1284 // we might have to hack this code first (depending on what order we do these bug fixes in). 1285 if (!m_captions.isEmpty()) { 1286 if (style()->isHorizontalWritingMode()) { 1287 rect.setHeight(height()); 1288 rect.setY(location.y()); 1289 } else { 1290 rect.setWidth(width()); 1291 rect.setX(location.x()); 1292 } 1293 } 1294 1295 return rect; 1296 } 1297 1298 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) 1299 { 1300 LayoutPoint adjustedLocation = accumulatedOffset + location(); 1301 1302 // Check kids first. 1303 if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation))) { 1304 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 1305 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) { 1306 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation); 1307 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) { 1308 updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint)); 1309 return true; 1310 } 1311 } 1312 } 1313 } 1314 1315 // Check our bounds next. 1316 LayoutRect boundsRect(adjustedLocation, size()); 1317 if (visibleToHitTestRequest(request) && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) { 1318 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation))); 1319 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect)) 1320 return true; 1321 } 1322 1323 return false; 1324 } 1325 1326 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent) 1327 { 1328 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE); 1329 RenderTable* newTable = new RenderTable(0); 1330 newTable->setDocumentForAnonymous(&parent->document()); 1331 newTable->setStyle(newStyle.release()); 1332 return newTable; 1333 } 1334 1335 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const 1336 { 1337 ASSERT(cell->isFirstOrLastCellInRow()); 1338 if (hasSameDirectionAs(cell->row())) 1339 return style()->borderStart(); 1340 1341 return style()->borderEnd(); 1342 } 1343 1344 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const 1345 { 1346 ASSERT(cell->isFirstOrLastCellInRow()); 1347 if (hasSameDirectionAs(cell->row())) 1348 return style()->borderEnd(); 1349 1350 return style()->borderStart(); 1351 } 1352 1353 } 1354