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