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