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 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 "RenderTable.h" 28 29 #include "AutoTableLayout.h" 30 #include "DeleteButtonController.h" 31 #include "Document.h" 32 #include "FixedTableLayout.h" 33 #include "FrameView.h" 34 #include "HTMLNames.h" 35 #include "RenderLayer.h" 36 #include "RenderTableCell.h" 37 #include "RenderTableCol.h" 38 #include "RenderTableSection.h" 39 #ifdef ANDROID_LAYOUT 40 #include "Settings.h" 41 #endif 42 #include "RenderView.h" 43 44 using namespace std; 45 46 namespace WebCore { 47 48 using namespace HTMLNames; 49 50 RenderTable::RenderTable(Node* node) 51 : RenderBlock(node) 52 , m_caption(0) 53 , m_head(0) 54 , m_foot(0) 55 , m_firstBody(0) 56 , m_currentBorder(0) 57 , m_hasColElements(false) 58 , m_needsSectionRecalc(0) 59 , m_hSpacing(0) 60 , m_vSpacing(0) 61 , m_borderLeft(0) 62 , m_borderRight(0) 63 { 64 #ifdef ANDROID_LAYOUT 65 m_singleColumn = false; 66 #endif 67 m_columnPos.fill(0, 2); 68 m_columns.fill(ColumnStruct(), 1); 69 } 70 71 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 72 { 73 RenderBlock::styleDidChange(diff, oldStyle); 74 75 ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO; 76 77 // In the collapsed border model, there is no cell spacing. 78 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing(); 79 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing(); 80 m_columnPos[0] = m_hSpacing; 81 82 if (!m_tableLayout || style()->tableLayout() != oldTableLayout) { 83 // According to the CSS2 spec, you only use fixed table layout if an 84 // explicit width is specified on the table. Auto width implies auto table layout. 85 if (style()->tableLayout() == TFIXED && !style()->width().isAuto()) 86 m_tableLayout.set(new FixedTableLayout(this)); 87 else 88 m_tableLayout.set(new AutoTableLayout(this)); 89 } 90 } 91 92 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before) 93 { 94 if (!before || !ptr) 95 return; 96 RenderObject* o = before->previousSibling(); 97 while (o && o != ptr) 98 o = o->previousSibling(); 99 if (!o) 100 ptr = 0; 101 } 102 103 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) 104 { 105 // Make sure we don't append things after :after-generated content if we have it. 106 if (!beforeChild && isAfterContent(lastChild())) 107 beforeChild = lastChild(); 108 109 bool wrapInAnonymousSection = !child->isPositioned(); 110 111 if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) { 112 // First caption wins. 113 if (beforeChild && m_caption) { 114 RenderObject* o = beforeChild->previousSibling(); 115 while (o && o != m_caption) 116 o = o->previousSibling(); 117 if (!o) 118 m_caption = 0; 119 } 120 if (!m_caption) 121 m_caption = toRenderBlock(child); 122 wrapInAnonymousSection = false; 123 } else if (child->isTableCol()) { 124 m_hasColElements = true; 125 wrapInAnonymousSection = false; 126 } else if (child->isTableSection()) { 127 switch (child->style()->display()) { 128 case TABLE_HEADER_GROUP: 129 resetSectionPointerIfNotBefore(m_head, beforeChild); 130 if (!m_head) { 131 m_head = toRenderTableSection(child); 132 } else { 133 resetSectionPointerIfNotBefore(m_firstBody, beforeChild); 134 if (!m_firstBody) 135 m_firstBody = toRenderTableSection(child); 136 } 137 wrapInAnonymousSection = false; 138 break; 139 case TABLE_FOOTER_GROUP: 140 resetSectionPointerIfNotBefore(m_foot, beforeChild); 141 if (!m_foot) { 142 m_foot = toRenderTableSection(child); 143 wrapInAnonymousSection = false; 144 break; 145 } 146 // Fall through. 147 case TABLE_ROW_GROUP: 148 resetSectionPointerIfNotBefore(m_firstBody, beforeChild); 149 if (!m_firstBody) 150 m_firstBody = toRenderTableSection(child); 151 wrapInAnonymousSection = false; 152 break; 153 default: 154 ASSERT_NOT_REACHED(); 155 } 156 } else if (child->isTableCell() || child->isTableRow()) 157 wrapInAnonymousSection = true; 158 else 159 wrapInAnonymousSection = true; 160 161 if (!wrapInAnonymousSection) { 162 // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that. 163 while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION) 164 beforeChild = beforeChild->parent(); 165 166 RenderBox::addChild(child, beforeChild); 167 return; 168 } 169 170 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) { 171 lastChild()->addChild(child); 172 return; 173 } 174 175 RenderObject* lastBox = beforeChild; 176 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP) 177 lastBox = lastBox->parent(); 178 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) { 179 lastBox->addChild(child, beforeChild); 180 return; 181 } 182 183 if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP) 184 beforeChild = 0; 185 RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */); 186 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 187 newStyle->inheritFrom(style()); 188 newStyle->setDisplay(TABLE_ROW_GROUP); 189 section->setStyle(newStyle.release()); 190 addChild(section, beforeChild); 191 section->addChild(child); 192 } 193 194 void RenderTable::removeChild(RenderObject* oldChild) 195 { 196 RenderBox::removeChild(oldChild); 197 setNeedsSectionRecalc(); 198 } 199 200 void RenderTable::calcWidth() 201 { 202 #ifdef ANDROID_LAYOUT 203 if (view()->frameView()) { 204 const Settings* settings = document()->settings(); 205 ASSERT(settings); 206 if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) { 207 m_visibleWidth = view()->frameView()->screenWidth(); 208 } 209 } 210 #endif 211 212 if (isPositioned()) 213 calcAbsoluteHorizontal(); 214 215 RenderBlock* cb = containingBlock(); 216 int availableWidth = cb->availableWidth(); 217 218 LengthType widthType = style()->width().type(); 219 if (widthType > Relative && style()->width().isPositive()) { 220 // Percent or fixed table 221 setWidth(style()->width().calcMinValue(availableWidth)); 222 setWidth(max(minPrefWidth(), width())); 223 } else { 224 // An auto width table should shrink to fit within the line width if necessary in order to 225 // avoid overlapping floats. 226 availableWidth = cb->lineWidth(y(), false); 227 228 // Subtract out any fixed margins from our available width for auto width tables. 229 int marginTotal = 0; 230 if (!style()->marginLeft().isAuto()) 231 marginTotal += style()->marginLeft().calcValue(availableWidth); 232 if (!style()->marginRight().isAuto()) 233 marginTotal += style()->marginRight().calcValue(availableWidth); 234 235 // Subtract out our margins to get the available content width. 236 int availContentWidth = max(0, availableWidth - marginTotal); 237 238 // Ensure we aren't bigger than our max width or smaller than our min width. 239 setWidth(min(availContentWidth, maxPrefWidth())); 240 } 241 242 setWidth(max(width(), minPrefWidth())); 243 244 // Finally, with our true width determined, compute our margins for real. 245 m_marginRight = 0; 246 m_marginLeft = 0; 247 #ifdef ANDROID_LAYOUT 248 // in SSR mode, we ignore left/right margin for table 249 if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) 250 return; 251 #endif 252 calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth); 253 } 254 255 void RenderTable::layout() 256 { 257 ASSERT(needsLayout()); 258 259 if (layoutOnlyPositionedObjects()) 260 return; 261 262 recalcSectionsIfNeeded(); 263 264 LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); 265 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); 266 267 setHeight(0); 268 m_overflow.clear(); 269 270 initMaxMarginValues(); 271 272 #ifdef ANDROID_LAYOUT 273 bool relayoutChildren = false; 274 int oldVisibleWidth = m_visibleWidth; 275 #endif 276 277 int oldWidth = width(); 278 calcWidth(); 279 280 #ifdef ANDROID_LAYOUT 281 if (oldVisibleWidth != m_visibleWidth 282 && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) 283 relayoutChildren = true; 284 else if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) { 285 // if the width of a table is wider than its container width, or it has a nested table, 286 // we will render it with single column. 287 int cw = containingBlockWidthForContent(); 288 bool shouldRenderAsSingleColumn = (width() > cw); 289 if (!shouldRenderAsSingleColumn) { 290 RenderObject* child = firstChild(); 291 while (child) { 292 if (child->isTable()) { 293 shouldRenderAsSingleColumn = true; 294 break; 295 } 296 child = child->nextInPreOrder(); 297 } 298 } 299 300 if (shouldRenderAsSingleColumn) { 301 m_singleColumn = true; 302 if (width() > cw) 303 setWidth(cw); 304 if (m_minPrefWidth > cw) 305 m_minPrefWidth = cw; 306 if (m_maxPrefWidth > cw) 307 m_maxPrefWidth = cw; 308 } 309 } 310 #endif 311 if (m_caption && width() != oldWidth) 312 m_caption->setNeedsLayout(true, false); 313 314 // FIXME: The optimisation below doesn't work since the internal table 315 // layout could have changed. we need to add a flag to the table 316 // layout that tells us if something has changed in the min max 317 // calculations to do it correctly. 318 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) 319 m_tableLayout->layout(); 320 321 setCellWidths(); 322 323 // layout child objects 324 int calculatedHeight = 0; 325 int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0; 326 327 bool collapsing = collapseBorders(); 328 329 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 330 #ifdef ANDROID_LAYOUT 331 if (relayoutChildren) { 332 child->setNeedsLayout(true, false); 333 if (!child->isTableSection()) { 334 child->layoutIfNeeded(); 335 continue; 336 } 337 // fall through 338 } 339 #endif 340 if (child->isTableSection()) { 341 child->layoutIfNeeded(); 342 RenderTableSection* section = toRenderTableSection(child); 343 calculatedHeight += section->calcRowHeight(); 344 if (collapsing) 345 section->recalcOuterBorder(); 346 ASSERT(!section->needsLayout()); 347 } else if (child->isTableCol()) { 348 child->layoutIfNeeded(); 349 ASSERT(!child->needsLayout()); 350 } 351 } 352 353 // Only lay out one caption, since it's the only one we're going to end up painting. 354 if (m_caption) 355 m_caption->layoutIfNeeded(); 356 357 // If any table section moved vertically, we will just repaint everything from that 358 // section down (it is quite unlikely that any of the following sections 359 // did not shift). 360 bool sectionMoved = false; 361 int movedSectionTop = 0; 362 363 // FIXME: Collapse caption margin. 364 if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { 365 IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); 366 367 m_caption->setLocation(m_caption->marginLeft(), height()); 368 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) 369 m_caption->repaintDuringLayoutIfMoved(captionRect); 370 371 setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); 372 373 if (height() != oldTableTop) { 374 sectionMoved = true; 375 movedSectionTop = min(height(), oldTableTop); 376 } 377 } 378 379 int bpTop = borderTop() + (collapsing ? 0 : paddingTop()); 380 int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom()); 381 382 setHeight(height() + bpTop); 383 384 if (!isPositioned()) 385 calcHeight(); 386 387 Length h = style()->height(); 388 int th = 0; 389 if (h.isFixed()) 390 // Tables size as though CSS height includes border/padding. 391 th = h.value() - (bpTop + bpBottom); 392 else if (h.isPercent()) 393 th = calcPercentageHeight(h); 394 th = max(0, th); 395 396 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 397 if (child->isTableSection()) 398 // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. 399 toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); 400 } 401 402 if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) { 403 // Completely empty tables (with no sections or anything) should at least honor specified height 404 // in strict mode. 405 setHeight(height() + th); 406 } 407 408 int bl = borderLeft(); 409 if (!collapsing) 410 bl += paddingLeft(); 411 412 // position the table sections 413 RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); 414 while (section) { 415 if (!sectionMoved && section->y() != height()) { 416 sectionMoved = true; 417 movedSectionTop = min(height(), section->y()) + section->topVisibleOverflow(); 418 } 419 section->setLocation(bl, height()); 420 421 setHeight(height() + section->height()); 422 section = sectionBelow(section); 423 } 424 425 setHeight(height() + bpBottom); 426 427 if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) { 428 IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); 429 430 m_caption->setLocation(m_caption->marginLeft(), height()); 431 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) 432 m_caption->repaintDuringLayoutIfMoved(captionRect); 433 434 setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); 435 } 436 437 if (isPositioned()) 438 calcHeight(); 439 440 // table can be containing block of positioned elements. 441 // FIXME: Only pass true if width or height changed. 442 layoutPositionedObjects(true); 443 444 // Add overflow from borders. 445 int rightBorderOverflow = width() + (collapsing ? outerBorderRight() - borderRight() : 0); 446 int leftBorderOverflow = collapsing ? borderLeft() - outerBorderLeft() : 0; 447 int bottomBorderOverflow = height() + (collapsing ? outerBorderBottom() - borderBottom() : 0); 448 int topBorderOverflow = collapsing ? borderTop() - outerBorderTop() : 0; 449 addLayoutOverflow(IntRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow)); 450 451 // Add visual overflow from box-shadow and reflections. 452 addShadowOverflow(); 453 454 // Add overflow from our caption. 455 if (m_caption) 456 addOverflowFromChild(m_caption); 457 458 // Add overflow from our sections. 459 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 460 if (child->isTableSection()) { 461 RenderTableSection* section = toRenderTableSection(child); 462 addOverflowFromChild(section); 463 } 464 } 465 466 statePusher.pop(); 467 468 bool didFullRepaint = repainter.repaintAfterLayout(); 469 // Repaint with our new bounds if they are different from our old bounds. 470 if (!didFullRepaint && sectionMoved) 471 repaintRectangle(IntRect(leftVisibleOverflow(), movedSectionTop, rightVisibleOverflow() - leftVisibleOverflow(), bottomVisibleOverflow() - movedSectionTop)); 472 473 setNeedsLayout(false); 474 } 475 476 void RenderTable::setCellWidths() 477 { 478 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 479 if (child->isTableSection()) 480 toRenderTableSection(child)->setCellWidths(); 481 } 482 } 483 484 void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) 485 { 486 tx += x(); 487 ty += y(); 488 489 PaintPhase paintPhase = paintInfo.phase; 490 491 int os = 2 * maximalOutlineSize(paintPhase); 492 if (ty + topVisibleOverflow() >= paintInfo.rect.bottom() + os || ty + bottomVisibleOverflow() <= paintInfo.rect.y() - os) 493 return; 494 if (tx + leftVisibleOverflow() >= paintInfo.rect.right() + os || tx + rightVisibleOverflow() <= paintInfo.rect.x() - os) 495 return; 496 497 bool pushedClip = pushContentsClip(paintInfo, tx, ty); 498 paintObject(paintInfo, tx, ty); 499 if (pushedClip) 500 popContentsClip(paintInfo, paintPhase, tx, ty); 501 } 502 503 void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) 504 { 505 PaintPhase paintPhase = paintInfo.phase; 506 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE) 507 paintBoxDecorations(paintInfo, tx, ty); 508 509 if (paintPhase == PaintPhaseMask) { 510 paintMask(paintInfo, tx, ty); 511 return; 512 } 513 514 // We're done. We don't bother painting any children. 515 if (paintPhase == PaintPhaseBlockBackground) 516 return; 517 518 // We don't paint our own background, but we do let the kids paint their backgrounds. 519 if (paintPhase == PaintPhaseChildBlockBackgrounds) 520 paintPhase = PaintPhaseChildBlockBackground; 521 522 PaintInfo info(paintInfo); 523 info.phase = paintPhase; 524 info.paintingRoot = paintingRootForChildren(paintInfo); 525 526 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 527 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) 528 child->paint(info, tx, ty); 529 } 530 531 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) { 532 // Collect all the unique border styles that we want to paint in a sorted list. Once we 533 // have all the styles sorted, we then do individual passes, painting each style of border 534 // from lowest precedence to highest precedence. 535 info.phase = PaintPhaseCollapsedTableBorders; 536 RenderTableCell::CollapsedBorderStyles borderStyles; 537 RenderObject* stop = nextInPreOrderAfterChildren(); 538 for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder()) 539 if (o->isTableCell()) 540 toRenderTableCell(o)->collectBorderStyles(borderStyles); 541 RenderTableCell::sortBorderStyles(borderStyles); 542 size_t count = borderStyles.size(); 543 for (size_t i = 0; i < count; ++i) { 544 m_currentBorder = &borderStyles[i]; 545 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) 546 if (child->isTableSection()) 547 child->paint(info, tx, ty); 548 } 549 m_currentBorder = 0; 550 } 551 } 552 553 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) 554 { 555 if (!shouldPaintWithinRoot(paintInfo)) 556 return; 557 558 int w = width(); 559 int h = height(); 560 561 // Account for the caption. 562 if (m_caption) { 563 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop()); 564 h -= captionHeight; 565 if (m_caption->style()->captionSide() != CAPBOTTOM) 566 ty += captionHeight; 567 } 568 569 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); 570 571 paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); 572 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); 573 574 if (style()->hasBorder() && !collapseBorders()) 575 paintBorder(paintInfo.context, tx, ty, w, h, style()); 576 } 577 578 void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty) 579 { 580 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) 581 return; 582 583 int w = width(); 584 int h = height(); 585 586 // Account for the caption. 587 if (m_caption) { 588 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop()); 589 h -= captionHeight; 590 if (m_caption->style()->captionSide() != CAPBOTTOM) 591 ty += captionHeight; 592 } 593 594 paintMaskImages(paintInfo, tx, ty, w, h); 595 } 596 597 void RenderTable::calcPrefWidths() 598 { 599 ASSERT(prefWidthsDirty()); 600 601 recalcSectionsIfNeeded(); 602 recalcHorizontalBorders(); 603 604 m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth); 605 606 if (m_caption) 607 m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth()); 608 609 setPrefWidthsDirty(false); 610 } 611 612 void RenderTable::splitColumn(int pos, int firstSpan) 613 { 614 // we need to add a new columnStruct 615 int oldSize = m_columns.size(); 616 m_columns.grow(oldSize + 1); 617 int oldSpan = m_columns[pos].span; 618 ASSERT(oldSpan > firstSpan); 619 m_columns[pos].span = firstSpan; 620 memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct)); 621 m_columns[pos + 1].span = oldSpan - firstSpan; 622 623 // change width of all rows. 624 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 625 if (child->isTableSection()) 626 toRenderTableSection(child)->splitColumn(pos, oldSize + 1); 627 } 628 629 m_columnPos.grow(numEffCols() + 1); 630 setNeedsLayoutAndPrefWidthsRecalc(); 631 } 632 633 void RenderTable::appendColumn(int span) 634 { 635 // easy case. 636 int pos = m_columns.size(); 637 int newSize = pos + 1; 638 m_columns.grow(newSize); 639 m_columns[pos].span = span; 640 641 // change width of all rows. 642 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 643 if (child->isTableSection()) 644 toRenderTableSection(child)->appendColumn(pos); 645 } 646 647 m_columnPos.grow(numEffCols() + 1); 648 setNeedsLayoutAndPrefWidthsRecalc(); 649 } 650 651 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const 652 { 653 if (!m_hasColElements) 654 return 0; 655 RenderObject* child = firstChild(); 656 int cCol = 0; 657 658 while (child) { 659 if (child->isTableCol()) { 660 RenderTableCol* colElem = toRenderTableCol(child); 661 int span = colElem->span(); 662 if (!colElem->firstChild()) { 663 int startCol = cCol; 664 int endCol = cCol + span - 1; 665 cCol += span; 666 if (cCol > col) { 667 if (startEdge) 668 *startEdge = startCol == col; 669 if (endEdge) 670 *endEdge = endCol == col; 671 return colElem; 672 } 673 } 674 675 RenderObject* next = child->firstChild(); 676 if (!next) 677 next = child->nextSibling(); 678 if (!next && child->parent()->isTableCol()) 679 next = child->parent()->nextSibling(); 680 child = next; 681 } else if (child == m_caption) 682 child = child->nextSibling(); 683 else 684 break; 685 } 686 687 return 0; 688 } 689 690 void RenderTable::recalcSections() const 691 { 692 m_caption = 0; 693 m_head = 0; 694 m_foot = 0; 695 m_firstBody = 0; 696 m_hasColElements = false; 697 698 // We need to get valid pointers to caption, head, foot and first body again 699 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 700 switch (child->style()->display()) { 701 case TABLE_CAPTION: 702 if (!m_caption && child->isRenderBlock()) { 703 m_caption = toRenderBlock(child); 704 m_caption->setNeedsLayout(true); 705 } 706 break; 707 case TABLE_COLUMN: 708 case TABLE_COLUMN_GROUP: 709 m_hasColElements = true; 710 break; 711 case TABLE_HEADER_GROUP: 712 if (child->isTableSection()) { 713 RenderTableSection* section = toRenderTableSection(child); 714 if (!m_head) 715 m_head = section; 716 else if (!m_firstBody) 717 m_firstBody = section; 718 section->recalcCellsIfNeeded(); 719 } 720 break; 721 case TABLE_FOOTER_GROUP: 722 if (child->isTableSection()) { 723 RenderTableSection* section = toRenderTableSection(child); 724 if (!m_foot) 725 m_foot = section; 726 else if (!m_firstBody) 727 m_firstBody = section; 728 section->recalcCellsIfNeeded(); 729 } 730 break; 731 case TABLE_ROW_GROUP: 732 if (child->isTableSection()) { 733 RenderTableSection* section = toRenderTableSection(child); 734 if (!m_firstBody) 735 m_firstBody = section; 736 section->recalcCellsIfNeeded(); 737 } 738 break; 739 default: 740 break; 741 } 742 } 743 744 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section) 745 int maxCols = 0; 746 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 747 if (child->isTableSection()) { 748 RenderTableSection* section = toRenderTableSection(child); 749 int sectionCols = section->numColumns(); 750 if (sectionCols > maxCols) 751 maxCols = sectionCols; 752 } 753 } 754 755 m_columns.resize(maxCols); 756 m_columnPos.resize(maxCols + 1); 757 758 ASSERT(selfNeedsLayout()); 759 760 m_needsSectionRecalc = false; 761 } 762 763 int RenderTable::calcBorderLeft() const 764 { 765 if (collapseBorders()) { 766 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2. 767 if (!numEffCols()) 768 return 0; 769 770 unsigned borderWidth = 0; 771 772 const BorderValue& tb = style()->borderLeft(); 773 if (tb.style() == BHIDDEN) 774 return 0; 775 if (tb.style() > BHIDDEN) 776 borderWidth = tb.width; 777 778 int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0; 779 RenderTableCol* colGroup = colElement(leftmostColumn); 780 if (colGroup) { 781 const BorderValue& gb = style()->borderLeft(); 782 if (gb.style() == BHIDDEN) 783 return 0; 784 if (gb.style() > BHIDDEN) 785 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width)); 786 } 787 788 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); 789 if (firstNonEmptySection && !firstNonEmptySection->numRows()) 790 firstNonEmptySection = sectionBelow(firstNonEmptySection, true); 791 792 if (firstNonEmptySection) { 793 const BorderValue& sb = firstNonEmptySection->style()->borderLeft(); 794 if (sb.style() == BHIDDEN) 795 return 0; 796 797 if (sb.style() > BHIDDEN) 798 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width)); 799 800 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn); 801 802 if (cs.cell) { 803 const BorderValue& cb = cs.cell->style()->borderLeft(); 804 if (cb.style() == BHIDDEN) 805 return 0; 806 807 const BorderValue& rb = cs.cell->parent()->style()->borderLeft(); 808 if (rb.style() == BHIDDEN) 809 return 0; 810 811 if (cb.style() > BHIDDEN) 812 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width)); 813 if (rb.style() > BHIDDEN) 814 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width)); 815 } 816 } 817 return borderWidth / 2; 818 } 819 return RenderBlock::borderLeft(); 820 } 821 822 int RenderTable::calcBorderRight() const 823 { 824 if (collapseBorders()) { 825 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2. 826 if (!numEffCols()) 827 return 0; 828 829 unsigned borderWidth = 0; 830 831 const BorderValue& tb = style()->borderRight(); 832 if (tb.style() == BHIDDEN) 833 return 0; 834 if (tb.style() > BHIDDEN) 835 borderWidth = tb.width; 836 837 int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1; 838 RenderTableCol* colGroup = colElement(rightmostColumn); 839 if (colGroup) { 840 const BorderValue& gb = style()->borderRight(); 841 if (gb.style() == BHIDDEN) 842 return 0; 843 if (gb.style() > BHIDDEN) 844 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width)); 845 } 846 847 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); 848 if (firstNonEmptySection && !firstNonEmptySection->numRows()) 849 firstNonEmptySection = sectionBelow(firstNonEmptySection, true); 850 851 if (firstNonEmptySection) { 852 const BorderValue& sb = firstNonEmptySection->style()->borderRight(); 853 if (sb.style() == BHIDDEN) 854 return 0; 855 856 if (sb.style() > BHIDDEN) 857 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width)); 858 859 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn); 860 861 if (cs.cell) { 862 const BorderValue& cb = cs.cell->style()->borderRight(); 863 if (cb.style() == BHIDDEN) 864 return 0; 865 866 const BorderValue& rb = cs.cell->parent()->style()->borderRight(); 867 if (rb.style() == BHIDDEN) 868 return 0; 869 870 if (cb.style() > BHIDDEN) 871 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width)); 872 if (rb.style() > BHIDDEN) 873 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width)); 874 } 875 } 876 return (borderWidth + 1) / 2; 877 } 878 return RenderBlock::borderRight(); 879 } 880 881 void RenderTable::recalcHorizontalBorders() 882 { 883 m_borderLeft = calcBorderLeft(); 884 m_borderRight = calcBorderRight(); 885 } 886 887 int RenderTable::borderTop() const 888 { 889 if (collapseBorders()) 890 return outerBorderTop(); 891 return RenderBlock::borderTop(); 892 } 893 894 int RenderTable::borderBottom() const 895 { 896 if (collapseBorders()) 897 return outerBorderBottom(); 898 return RenderBlock::borderBottom(); 899 } 900 901 int RenderTable::outerBorderTop() const 902 { 903 if (!collapseBorders()) 904 return 0; 905 int borderWidth = 0; 906 RenderTableSection* topSection; 907 if (m_head) 908 topSection = m_head; 909 else if (m_firstBody) 910 topSection = m_firstBody; 911 else if (m_foot) 912 topSection = m_foot; 913 else 914 topSection = 0; 915 if (topSection) { 916 borderWidth = topSection->outerBorderTop(); 917 if (borderWidth == -1) 918 return 0; // Overridden by hidden 919 } 920 const BorderValue& tb = style()->borderTop(); 921 if (tb.style() == BHIDDEN) 922 return 0; 923 if (tb.style() > BHIDDEN) 924 borderWidth = max(borderWidth, static_cast<int>(tb.width / 2)); 925 return borderWidth; 926 } 927 928 int RenderTable::outerBorderBottom() const 929 { 930 if (!collapseBorders()) 931 return 0; 932 int borderWidth = 0; 933 RenderTableSection* bottomSection; 934 if (m_foot) 935 bottomSection = m_foot; 936 else { 937 RenderObject* child; 938 for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { } 939 bottomSection = child ? toRenderTableSection(child) : 0; 940 } 941 if (bottomSection) { 942 borderWidth = bottomSection->outerBorderBottom(); 943 if (borderWidth == -1) 944 return 0; // Overridden by hidden 945 } 946 const BorderValue& tb = style()->borderBottom(); 947 if (tb.style() == BHIDDEN) 948 return 0; 949 if (tb.style() > BHIDDEN) 950 borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2)); 951 return borderWidth; 952 } 953 954 int RenderTable::outerBorderLeft() const 955 { 956 if (!collapseBorders()) 957 return 0; 958 959 int borderWidth = 0; 960 961 const BorderValue& tb = style()->borderLeft(); 962 if (tb.style() == BHIDDEN) 963 return 0; 964 if (tb.style() > BHIDDEN) 965 borderWidth = tb.width / 2; 966 967 bool allHidden = true; 968 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 969 if (!child->isTableSection()) 970 continue; 971 int sw = toRenderTableSection(child)->outerBorderLeft(); 972 if (sw == -1) 973 continue; 974 else 975 allHidden = false; 976 borderWidth = max(borderWidth, sw); 977 } 978 if (allHidden) 979 return 0; 980 981 return borderWidth; 982 } 983 984 int RenderTable::outerBorderRight() const 985 { 986 if (!collapseBorders()) 987 return 0; 988 989 int borderWidth = 0; 990 991 const BorderValue& tb = style()->borderRight(); 992 if (tb.style() == BHIDDEN) 993 return 0; 994 if (tb.style() > BHIDDEN) 995 borderWidth = (tb.width + 1) / 2; 996 997 bool allHidden = true; 998 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 999 if (!child->isTableSection()) 1000 continue; 1001 int sw = toRenderTableSection(child)->outerBorderRight(); 1002 if (sw == -1) 1003 continue; 1004 else 1005 allHidden = false; 1006 borderWidth = max(borderWidth, sw); 1007 } 1008 if (allHidden) 1009 return 0; 1010 1011 return borderWidth; 1012 } 1013 1014 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const 1015 { 1016 recalcSectionsIfNeeded(); 1017 1018 if (section == m_head) 1019 return 0; 1020 1021 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling(); 1022 while (prevSection) { 1023 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || toRenderTableSection(prevSection)->numRows())) 1024 break; 1025 prevSection = prevSection->previousSibling(); 1026 } 1027 if (!prevSection && m_head && (!skipEmptySections || m_head->numRows())) 1028 prevSection = m_head; 1029 return toRenderTableSection(prevSection); 1030 } 1031 1032 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const 1033 { 1034 recalcSectionsIfNeeded(); 1035 1036 if (section == m_foot) 1037 return 0; 1038 1039 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling(); 1040 while (nextSection) { 1041 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || toRenderTableSection(nextSection)->numRows())) 1042 break; 1043 nextSection = nextSection->nextSibling(); 1044 } 1045 if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows())) 1046 nextSection = m_foot; 1047 return toRenderTableSection(nextSection); 1048 } 1049 1050 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const 1051 { 1052 recalcSectionsIfNeeded(); 1053 1054 // Find the section and row to look in 1055 int r = cell->row(); 1056 RenderTableSection* section = 0; 1057 int rAbove = 0; 1058 if (r > 0) { 1059 // cell is not in the first row, so use the above row in its own section 1060 section = cell->section(); 1061 rAbove = r - 1; 1062 } else { 1063 section = sectionAbove(cell->section(), true); 1064 if (section) 1065 rAbove = section->numRows() - 1; 1066 } 1067 1068 // Look up the cell in the section's grid, which requires effective col index 1069 if (section) { 1070 int effCol = colToEffCol(cell->col()); 1071 RenderTableSection::CellStruct aboveCell; 1072 // If we hit a span back up to a real cell. 1073 do { 1074 aboveCell = section->cellAt(rAbove, effCol); 1075 effCol--; 1076 } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0); 1077 return aboveCell.cell; 1078 } else 1079 return 0; 1080 } 1081 1082 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const 1083 { 1084 recalcSectionsIfNeeded(); 1085 1086 // Find the section and row to look in 1087 int r = cell->row() + cell->rowSpan() - 1; 1088 RenderTableSection* section = 0; 1089 int rBelow = 0; 1090 if (r < cell->section()->numRows() - 1) { 1091 // The cell is not in the last row, so use the next row in the section. 1092 section = cell->section(); 1093 rBelow = r + 1; 1094 } else { 1095 section = sectionBelow(cell->section(), true); 1096 if (section) 1097 rBelow = 0; 1098 } 1099 1100 // Look up the cell in the section's grid, which requires effective col index 1101 if (section) { 1102 int effCol = colToEffCol(cell->col()); 1103 RenderTableSection::CellStruct belowCell; 1104 // If we hit a colspan back up to a real cell. 1105 do { 1106 belowCell = section->cellAt(rBelow, effCol); 1107 effCol--; 1108 } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0); 1109 return belowCell.cell; 1110 } else 1111 return 0; 1112 } 1113 1114 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const 1115 { 1116 recalcSectionsIfNeeded(); 1117 1118 RenderTableSection* section = cell->section(); 1119 int effCol = colToEffCol(cell->col()); 1120 if (!effCol) 1121 return 0; 1122 1123 // If we hit a colspan back up to a real cell. 1124 RenderTableSection::CellStruct prevCell; 1125 do { 1126 prevCell = section->cellAt(cell->row(), effCol - 1); 1127 effCol--; 1128 } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0); 1129 return prevCell.cell; 1130 } 1131 1132 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const 1133 { 1134 recalcSectionsIfNeeded(); 1135 1136 int effCol = colToEffCol(cell->col() + cell->colSpan()); 1137 if (effCol >= numEffCols()) 1138 return 0; 1139 return cell->section()->cellAt(cell->row(), effCol).cell; 1140 } 1141 1142 RenderBlock* RenderTable::firstLineBlock() const 1143 { 1144 return 0; 1145 } 1146 1147 void RenderTable::updateFirstLetter() 1148 { 1149 } 1150 1151 int RenderTable::firstLineBoxBaseline() const 1152 { 1153 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); 1154 if (firstNonEmptySection && !firstNonEmptySection->numRows()) 1155 firstNonEmptySection = sectionBelow(firstNonEmptySection, true); 1156 1157 if (!firstNonEmptySection) 1158 return -1; 1159 1160 return firstNonEmptySection->y() + firstNonEmptySection->firstLineBoxBaseline(); 1161 } 1162 1163 IntRect RenderTable::overflowClipRect(int tx, int ty) 1164 { 1165 IntRect rect = RenderBlock::overflowClipRect(tx, ty); 1166 1167 // If we have a caption, expand the clip to include the caption. 1168 // FIXME: Technically this is wrong, but it's virtually impossible to fix this 1169 // for real until captions have been re-written. 1170 // FIXME: This code assumes (like all our other caption code) that only top/bottom are 1171 // supported. When we actually support left/right and stop mapping them to top/bottom, 1172 // we might have to hack this code first (depending on what order we do these bug fixes in). 1173 if (m_caption) { 1174 rect.setHeight(height()); 1175 rect.setY(ty); 1176 } 1177 1178 return rect; 1179 } 1180 1181 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) 1182 { 1183 tx += x(); 1184 ty += y(); 1185 1186 // Check kids first. 1187 if (!hasOverflowClip() || overflowClipRect(tx, ty).contains(xPos, yPos)) { 1188 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 1189 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) && 1190 child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { 1191 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); 1192 return true; 1193 } 1194 } 1195 } 1196 1197 // Check our bounds next. 1198 if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) { 1199 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); 1200 return true; 1201 } 1202 1203 return false; 1204 } 1205 1206 } 1207