• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     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 
resetSectionPointerIfNotBefore(RenderTableSection * & ptr,RenderObject * before)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 
addChild(RenderObject * child,RenderObject * beforeChild)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 
removeChild(RenderObject * oldChild)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 
computeLogicalWidth()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 
adjustLogicalHeightForCaption()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 
layout()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 
addOverflowFromChildren()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 
setCellLogicalWidths()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 
paint(PaintInfo & paintInfo,int tx,int ty)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 
paintObject(PaintInfo & paintInfo,int tx,int ty)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 
subtractCaptionRect(IntRect & rect) const595 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 
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)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 
paintMask(PaintInfo & paintInfo,int tx,int ty)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 
computePreferredLogicalWidths()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 
splitColumn(int pos,int firstSpan)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 
appendColumn(int span)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 
nextColElement(RenderTableCol * current) const701 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 
colElement(int col,bool * startEdge,bool * endEdge) const720 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 
recalcCaption(RenderBlock * caption) const758 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 
recalcSections() const773 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 
calcBorderStart() const846 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 
calcBorderEnd() const903 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 
recalcBordersInRowDirection()961 void RenderTable::recalcBordersInRowDirection()
962 {
963     m_borderStart = calcBorderStart();
964     m_borderEnd = calcBorderEnd();
965 }
966 
borderBefore() const967 int RenderTable::borderBefore() const
968 {
969     if (collapseBorders())
970         return outerBorderBefore();
971     return RenderBlock::borderBefore();
972 }
973 
borderAfter() const974 int RenderTable::borderAfter() const
975 {
976     if (collapseBorders())
977         return outerBorderAfter();
978     return RenderBlock::borderAfter();
979 }
980 
outerBorderBefore() const981 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 
outerBorderAfter() const1008 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 
outerBorderStart() const1034 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 
outerBorderEnd() const1064 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 
sectionAbove(const RenderTableSection * section,bool skipEmptySections) const1094 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 
sectionBelow(const RenderTableSection * section,bool skipEmptySections) const1112 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 
cellAbove(const RenderTableCell * cell) const1130 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 
cellBelow(const RenderTableCell * cell) const1157 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 
cellBefore(const RenderTableCell * cell) const1184 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 
cellAfter(const RenderTableCell * cell) const1198 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 
firstLineBlock() const1208 RenderBlock* RenderTable::firstLineBlock() const
1209 {
1210     return 0;
1211 }
1212 
updateFirstLetter()1213 void RenderTable::updateFirstLetter()
1214 {
1215 }
1216 
firstLineBoxBaseline() const1217 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 
overflowClipRect(int tx,int ty,OverlayScrollbarSizeRelevancy relevancy)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 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction action)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