1 /*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 * (C) 1997 Torben Weis (weis@kde.org)
4 * (C) 1998 Waldo Bastian (bastian@kde.org)
5 * (C) 1999 Lars Knoll (knoll@kde.org)
6 * (C) 1999 Antti Koivisto (koivisto@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@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
RenderTable(Node * node)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
~RenderTable()75 RenderTable::~RenderTable()
76 {
77 }
78
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)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
resetSectionPointerIfNotBefore(RenderTableSection * & ptr,RenderObject * before)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
addChild(RenderObject * child,RenderObject * beforeChild)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
removeChild(RenderObject * oldChild)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
computeLogicalWidth()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
adjustLogicalHeightForCaption()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
layout()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
addOverflowFromChildren()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
setCellLogicalWidths()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
paint(PaintInfo & paintInfo,int tx,int ty)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
paintObject(PaintInfo & paintInfo,int tx,int ty)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
subtractCaptionRect(IntRect & rect) const594 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
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)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
paintMask(PaintInfo & paintInfo,int tx,int ty)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
computePreferredLogicalWidths()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
splitColumn(int pos,int firstSpan)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
appendColumn(int span)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
nextColElement(RenderTableCol * current) const700 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
colElement(int col,bool * startEdge,bool * endEdge) const719 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
recalcCaption(RenderBlock * caption) const757 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
recalcSections() const772 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
calcBorderStart() const845 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
calcBorderEnd() const902 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
recalcBordersInRowDirection()960 void RenderTable::recalcBordersInRowDirection()
961 {
962 m_borderStart = calcBorderStart();
963 m_borderEnd = calcBorderEnd();
964 }
965
borderBefore() const966 int RenderTable::borderBefore() const
967 {
968 if (collapseBorders())
969 return outerBorderBefore();
970 return RenderBlock::borderBefore();
971 }
972
borderAfter() const973 int RenderTable::borderAfter() const
974 {
975 if (collapseBorders())
976 return outerBorderAfter();
977 return RenderBlock::borderAfter();
978 }
979
outerBorderBefore() const980 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
outerBorderAfter() const1007 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
outerBorderStart() const1033 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
outerBorderEnd() const1063 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
sectionAbove(const RenderTableSection * section,bool skipEmptySections) const1093 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
sectionBelow(const RenderTableSection * section,bool skipEmptySections) const1111 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
cellAbove(const RenderTableCell * cell) const1129 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
cellBelow(const RenderTableCell * cell) const1156 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
cellBefore(const RenderTableCell * cell) const1183 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
cellAfter(const RenderTableCell * cell) const1197 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
firstLineBlock() const1207 RenderBlock* RenderTable::firstLineBlock() const
1208 {
1209 return 0;
1210 }
1211
updateFirstLetter()1212 void RenderTable::updateFirstLetter()
1213 {
1214 }
1215
firstLineBoxBaseline() const1216 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
overflowClipRect(int tx,int ty,OverlayScrollbarSizeRelevancy relevancy)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
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction action)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