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