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