• 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_overflowHeight = 0;
269     m_overflowTop = 0;
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     m_overflowWidth = width() + (collapsing ? outerBorderRight() - borderRight() : 0);
358     m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0;
359 
360     // If any table section moved vertically, we will just repaint everything from that
361     // section down (it is quite unlikely that any of the following sections
362     // did not shift).
363     bool sectionMoved = false;
364     int movedSectionTop = 0;
365 
366     // FIXME: Collapse caption margin.
367     if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
368         IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
369 
370         m_caption->setLocation(m_caption->marginLeft(), height());
371         if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
372             m_caption->repaintDuringLayoutIfMoved(captionRect);
373 
374         setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
375         m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));
376         m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false));
377         m_overflowTop = min(m_overflowTop, m_caption->y() + m_caption->overflowTop(false));
378         m_overflowHeight = max(m_overflowHeight, m_caption->y() + m_caption->overflowHeight(false));
379 
380         if (height() != oldTableTop) {
381             sectionMoved = true;
382             movedSectionTop = min(height(), oldTableTop);
383         }
384     }
385 
386     int bpTop = borderTop() + (collapsing ? 0 : paddingTop());
387     int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom());
388 
389     setHeight(height() + bpTop);
390 
391     if (!isPositioned())
392         calcHeight();
393 
394     Length h = style()->height();
395     int th = 0;
396     if (h.isFixed())
397         // Tables size as though CSS height includes border/padding.
398         th = h.value() - (bpTop + bpBottom);
399     else if (h.isPercent())
400         th = calcPercentageHeight(h);
401     th = max(0, th);
402 
403     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
404         if (child->isTableSection())
405             // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
406             toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0);
407     }
408 
409     if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) {
410         // Completely empty tables (with no sections or anything) should at least honor specified height
411         // in strict mode.
412         setHeight(height() + th);
413     }
414 
415     int bl = borderLeft();
416     if (!collapsing)
417         bl += paddingLeft();
418 
419     // position the table sections
420     RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
421     while (section) {
422         if (!sectionMoved && section->y() != height()) {
423             sectionMoved = true;
424             movedSectionTop = min(height(), section->y()) + section->overflowTop(false);
425         }
426         section->setLocation(bl, height());
427 
428         setHeight(height() + section->height());
429         m_overflowLeft = min(m_overflowLeft, section->x() + section->overflowLeft(false));
430         m_overflowWidth = max(m_overflowWidth, section->x() + section->overflowWidth(false));
431         m_overflowTop = min(m_overflowTop, section->y() + section->overflowTop(false));
432         m_overflowHeight = max(m_overflowHeight, section->y() + section->overflowHeight(false));
433         section = sectionBelow(section);
434     }
435 
436     setHeight(height() + bpBottom);
437 
438     if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
439         IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
440 
441         m_caption->setLocation(m_caption->marginLeft(), height());
442         if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
443             m_caption->repaintDuringLayoutIfMoved(captionRect);
444 
445         setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
446         m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));
447         m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false));
448     }
449 
450     if (isPositioned())
451         calcHeight();
452 
453     m_overflowHeight = max(m_overflowHeight, height());
454 
455     // table can be containing block of positioned elements.
456     // FIXME: Only pass true if width or height changed.
457     layoutPositionedObjects(true);
458 
459     if (!hasOverflowClip()) {
460         int shadowLeft;
461         int shadowRight;
462         int shadowTop;
463         int shadowBottom;
464         style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
465 
466         m_overflowLeft = min(m_overflowLeft, shadowLeft);
467         m_overflowWidth = max(m_overflowWidth, width() + shadowRight);
468         m_overflowTop = min(m_overflowTop, shadowTop);
469         m_overflowHeight = max(m_overflowHeight, height() + shadowBottom);
470 
471         if (hasReflection()) {
472             IntRect reflection(reflectionBox());
473             m_overflowTop = min(m_overflowTop, reflection.y());
474             m_overflowHeight = max(m_overflowHeight, reflection.bottom());
475             m_overflowLeft = min(m_overflowLeft, reflection.x());
476             m_overflowHeight = max(m_overflowWidth, reflection.right());
477         }
478     }
479 
480     statePusher.pop();
481 
482     bool didFullRepaint = repainter.repaintAfterLayout();
483     // Repaint with our new bounds if they are different from our old bounds.
484     if (!didFullRepaint && sectionMoved)
485         repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop));
486 
487     setNeedsLayout(false);
488 }
489 
setCellWidths()490 void RenderTable::setCellWidths()
491 {
492     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
493         if (child->isTableSection())
494             toRenderTableSection(child)->setCellWidths();
495     }
496 }
497 
paint(PaintInfo & paintInfo,int tx,int ty)498 void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
499 {
500     tx += x();
501     ty += y();
502 
503     PaintPhase paintPhase = paintInfo.phase;
504 
505     int os = 2 * maximalOutlineSize(paintPhase);
506     if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
507         return;
508     if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
509         return;
510 
511     bool pushedClip = pushContentsClip(paintInfo, tx, ty);
512     paintObject(paintInfo, tx, ty);
513     if (pushedClip)
514         popContentsClip(paintInfo, paintPhase, tx, ty);
515 }
516 
paintObject(PaintInfo & paintInfo,int tx,int ty)517 void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty)
518 {
519     PaintPhase paintPhase = paintInfo.phase;
520     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
521         paintBoxDecorations(paintInfo, tx, ty);
522 
523     if (paintPhase == PaintPhaseMask) {
524         paintMask(paintInfo, tx, ty);
525         return;
526     }
527 
528     // We're done.  We don't bother painting any children.
529     if (paintPhase == PaintPhaseBlockBackground)
530         return;
531 
532     // We don't paint our own background, but we do let the kids paint their backgrounds.
533     if (paintPhase == PaintPhaseChildBlockBackgrounds)
534         paintPhase = PaintPhaseChildBlockBackground;
535 
536     PaintInfo info(paintInfo);
537     info.phase = paintPhase;
538     info.paintingRoot = paintingRootForChildren(paintInfo);
539 
540     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
541         if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption))
542             child->paint(info, tx, ty);
543     }
544 
545     if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
546         // Collect all the unique border styles that we want to paint in a sorted list.  Once we
547         // have all the styles sorted, we then do individual passes, painting each style of border
548         // from lowest precedence to highest precedence.
549         info.phase = PaintPhaseCollapsedTableBorders;
550         RenderTableCell::CollapsedBorderStyles borderStyles;
551         RenderObject* stop = nextInPreOrderAfterChildren();
552         for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
553             if (o->isTableCell())
554                 toRenderTableCell(o)->collectBorderStyles(borderStyles);
555         RenderTableCell::sortBorderStyles(borderStyles);
556         size_t count = borderStyles.size();
557         for (size_t i = 0; i < count; ++i) {
558             m_currentBorder = &borderStyles[i];
559             for (RenderObject* child = firstChild(); child; child = child->nextSibling())
560                 if (child->isTableSection())
561                     child->paint(info, tx, ty);
562         }
563         m_currentBorder = 0;
564     }
565 }
566 
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)567 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
568 {
569     int w = width();
570     int h = height();
571 
572     // Account for the caption.
573     if (m_caption) {
574         int captionHeight = (m_caption->height() + m_caption->marginBottom() +  m_caption->marginTop());
575         h -= captionHeight;
576         if (m_caption->style()->captionSide() != CAPBOTTOM)
577             ty += captionHeight;
578     }
579 
580     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
581 
582     paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h);
583     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
584 
585     if (style()->hasBorder() && !collapseBorders())
586         paintBorder(paintInfo.context, tx, ty, w, h, style());
587 }
588 
paintMask(PaintInfo & paintInfo,int tx,int ty)589 void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty)
590 {
591     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
592         return;
593 
594     int w = width();
595     int h = height();
596 
597     // Account for the caption.
598     if (m_caption) {
599         int captionHeight = (m_caption->height() + m_caption->marginBottom() +  m_caption->marginTop());
600         h -= captionHeight;
601         if (m_caption->style()->captionSide() != CAPBOTTOM)
602             ty += captionHeight;
603     }
604 
605     paintMaskImages(paintInfo, tx, ty, w, h);
606 }
607 
calcPrefWidths()608 void RenderTable::calcPrefWidths()
609 {
610     ASSERT(prefWidthsDirty());
611 
612     recalcSectionsIfNeeded();
613     recalcHorizontalBorders();
614 
615     m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth);
616 
617     if (m_caption)
618         m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth());
619 
620     setPrefWidthsDirty(false);
621 }
622 
splitColumn(int pos,int firstSpan)623 void RenderTable::splitColumn(int pos, int firstSpan)
624 {
625     // we need to add a new columnStruct
626     int oldSize = m_columns.size();
627     m_columns.grow(oldSize + 1);
628     int oldSpan = m_columns[pos].span;
629     ASSERT(oldSpan > firstSpan);
630     m_columns[pos].span = firstSpan;
631     memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
632     m_columns[pos + 1].span = oldSpan - firstSpan;
633 
634     // change width of all rows.
635     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
636         if (child->isTableSection())
637             toRenderTableSection(child)->splitColumn(pos, oldSize + 1);
638     }
639 
640     m_columnPos.grow(numEffCols() + 1);
641     setNeedsLayoutAndPrefWidthsRecalc();
642 }
643 
appendColumn(int span)644 void RenderTable::appendColumn(int span)
645 {
646     // easy case.
647     int pos = m_columns.size();
648     int newSize = pos + 1;
649     m_columns.grow(newSize);
650     m_columns[pos].span = span;
651 
652     // change width of all rows.
653     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
654         if (child->isTableSection())
655             toRenderTableSection(child)->appendColumn(pos);
656     }
657 
658     m_columnPos.grow(numEffCols() + 1);
659     setNeedsLayoutAndPrefWidthsRecalc();
660 }
661 
colElement(int col,bool * startEdge,bool * endEdge) const662 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
663 {
664     if (!m_hasColElements)
665         return 0;
666     RenderObject* child = firstChild();
667     int cCol = 0;
668 
669     while (child) {
670         if (child->isTableCol()) {
671             RenderTableCol* colElem = toRenderTableCol(child);
672             int span = colElem->span();
673             if (!colElem->firstChild()) {
674                 int startCol = cCol;
675                 int endCol = cCol + span - 1;
676                 cCol += span;
677                 if (cCol > col) {
678                     if (startEdge)
679                         *startEdge = startCol == col;
680                     if (endEdge)
681                         *endEdge = endCol == col;
682                     return colElem;
683                 }
684             }
685 
686             RenderObject* next = child->firstChild();
687             if (!next)
688                 next = child->nextSibling();
689             if (!next && child->parent()->isTableCol())
690                 next = child->parent()->nextSibling();
691             child = next;
692         } else if (child == m_caption)
693             child = child->nextSibling();
694         else
695             break;
696     }
697 
698     return 0;
699 }
700 
recalcSections() const701 void RenderTable::recalcSections() const
702 {
703     m_caption = 0;
704     m_head = 0;
705     m_foot = 0;
706     m_firstBody = 0;
707     m_hasColElements = false;
708 
709     // We need to get valid pointers to caption, head, foot and first body again
710     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
711         switch (child->style()->display()) {
712             case TABLE_CAPTION:
713                 if (!m_caption && child->isRenderBlock()) {
714                     m_caption = toRenderBlock(child);
715                     m_caption->setNeedsLayout(true);
716                 }
717                 break;
718             case TABLE_COLUMN:
719             case TABLE_COLUMN_GROUP:
720                 m_hasColElements = true;
721                 break;
722             case TABLE_HEADER_GROUP:
723                 if (child->isTableSection()) {
724                     RenderTableSection* section = toRenderTableSection(child);
725                     if (!m_head)
726                         m_head = section;
727                     else if (!m_firstBody)
728                         m_firstBody = section;
729                     section->recalcCellsIfNeeded();
730                 }
731                 break;
732             case TABLE_FOOTER_GROUP:
733                 if (child->isTableSection()) {
734                     RenderTableSection* section = toRenderTableSection(child);
735                     if (!m_foot)
736                         m_foot = section;
737                     else if (!m_firstBody)
738                         m_firstBody = section;
739                     section->recalcCellsIfNeeded();
740                 }
741                 break;
742             case TABLE_ROW_GROUP:
743                 if (child->isTableSection()) {
744                     RenderTableSection* section = toRenderTableSection(child);
745                     if (!m_firstBody)
746                         m_firstBody = section;
747                     section->recalcCellsIfNeeded();
748                 }
749                 break;
750             default:
751                 break;
752         }
753     }
754 
755     // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
756     int maxCols = 0;
757     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
758         if (child->isTableSection()) {
759             RenderTableSection* section = toRenderTableSection(child);
760             int sectionCols = section->numColumns();
761             if (sectionCols > maxCols)
762                 maxCols = sectionCols;
763         }
764     }
765 
766     m_columns.resize(maxCols);
767     m_columnPos.resize(maxCols + 1);
768 
769     ASSERT(selfNeedsLayout());
770 
771     m_needsSectionRecalc = false;
772 }
773 
calcBorderLeft() const774 int RenderTable::calcBorderLeft() const
775 {
776     if (collapseBorders()) {
777         // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
778         if (!numEffCols())
779             return 0;
780 
781         unsigned borderWidth = 0;
782 
783         const BorderValue& tb = style()->borderLeft();
784         if (tb.style() == BHIDDEN)
785             return 0;
786         if (tb.style() > BHIDDEN)
787             borderWidth = tb.width;
788 
789         int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
790         RenderTableCol* colGroup = colElement(leftmostColumn);
791         if (colGroup) {
792             const BorderValue& gb = style()->borderLeft();
793             if (gb.style() == BHIDDEN)
794                 return 0;
795             if (gb.style() > BHIDDEN)
796                 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
797         }
798 
799         RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
800         if (firstNonEmptySection && !firstNonEmptySection->numRows())
801             firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
802 
803         if (firstNonEmptySection) {
804             const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
805             if (sb.style() == BHIDDEN)
806                 return 0;
807 
808             if (sb.style() > BHIDDEN)
809                 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
810 
811             const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
812 
813             if (cs.cell) {
814                 const BorderValue& cb = cs.cell->style()->borderLeft();
815                 if (cb.style() == BHIDDEN)
816                     return 0;
817 
818                 const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
819                 if (rb.style() == BHIDDEN)
820                     return 0;
821 
822                 if (cb.style() > BHIDDEN)
823                     borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
824                 if (rb.style() > BHIDDEN)
825                     borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
826             }
827         }
828         return borderWidth / 2;
829     }
830     return RenderBlock::borderLeft();
831 }
832 
calcBorderRight() const833 int RenderTable::calcBorderRight() const
834 {
835     if (collapseBorders()) {
836         // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
837         if (!numEffCols())
838             return 0;
839 
840         unsigned borderWidth = 0;
841 
842         const BorderValue& tb = style()->borderRight();
843         if (tb.style() == BHIDDEN)
844             return 0;
845         if (tb.style() > BHIDDEN)
846             borderWidth = tb.width;
847 
848         int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
849         RenderTableCol* colGroup = colElement(rightmostColumn);
850         if (colGroup) {
851             const BorderValue& gb = style()->borderRight();
852             if (gb.style() == BHIDDEN)
853                 return 0;
854             if (gb.style() > BHIDDEN)
855                 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
856         }
857 
858         RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
859         if (firstNonEmptySection && !firstNonEmptySection->numRows())
860             firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
861 
862         if (firstNonEmptySection) {
863             const BorderValue& sb = firstNonEmptySection->style()->borderRight();
864             if (sb.style() == BHIDDEN)
865                 return 0;
866 
867             if (sb.style() > BHIDDEN)
868                 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
869 
870             const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
871 
872             if (cs.cell) {
873                 const BorderValue& cb = cs.cell->style()->borderRight();
874                 if (cb.style() == BHIDDEN)
875                     return 0;
876 
877                 const BorderValue& rb = cs.cell->parent()->style()->borderRight();
878                 if (rb.style() == BHIDDEN)
879                     return 0;
880 
881                 if (cb.style() > BHIDDEN)
882                     borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
883                 if (rb.style() > BHIDDEN)
884                     borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
885             }
886         }
887         return (borderWidth + 1) / 2;
888     }
889     return RenderBlock::borderRight();
890 }
891 
recalcHorizontalBorders()892 void RenderTable::recalcHorizontalBorders()
893 {
894     m_borderLeft = calcBorderLeft();
895     m_borderRight = calcBorderRight();
896 }
897 
borderTop() const898 int RenderTable::borderTop() const
899 {
900     if (collapseBorders())
901         return outerBorderTop();
902     return RenderBlock::borderTop();
903 }
904 
borderBottom() const905 int RenderTable::borderBottom() const
906 {
907     if (collapseBorders())
908         return outerBorderBottom();
909     return RenderBlock::borderBottom();
910 }
911 
outerBorderTop() const912 int RenderTable::outerBorderTop() const
913 {
914     if (!collapseBorders())
915         return 0;
916     int borderWidth = 0;
917     RenderTableSection* topSection;
918     if (m_head)
919         topSection = m_head;
920     else if (m_firstBody)
921         topSection = m_firstBody;
922     else if (m_foot)
923         topSection = m_foot;
924     else
925         topSection = 0;
926     if (topSection) {
927         borderWidth = topSection->outerBorderTop();
928         if (borderWidth == -1)
929             return 0;   // Overridden by hidden
930     }
931     const BorderValue& tb = style()->borderTop();
932     if (tb.style() == BHIDDEN)
933         return 0;
934     if (tb.style() > BHIDDEN)
935         borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
936     return borderWidth;
937 }
938 
outerBorderBottom() const939 int RenderTable::outerBorderBottom() const
940 {
941     if (!collapseBorders())
942         return 0;
943     int borderWidth = 0;
944     RenderTableSection* bottomSection;
945     if (m_foot)
946         bottomSection = m_foot;
947     else {
948         RenderObject* child;
949         for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { }
950         bottomSection = child ? toRenderTableSection(child) : 0;
951     }
952     if (bottomSection) {
953         borderWidth = bottomSection->outerBorderBottom();
954         if (borderWidth == -1)
955             return 0;   // Overridden by hidden
956     }
957     const BorderValue& tb = style()->borderBottom();
958     if (tb.style() == BHIDDEN)
959         return 0;
960     if (tb.style() > BHIDDEN)
961         borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
962     return borderWidth;
963 }
964 
outerBorderLeft() const965 int RenderTable::outerBorderLeft() const
966 {
967     if (!collapseBorders())
968         return 0;
969 
970     int borderWidth = 0;
971 
972     const BorderValue& tb = style()->borderLeft();
973     if (tb.style() == BHIDDEN)
974         return 0;
975     if (tb.style() > BHIDDEN)
976         borderWidth = tb.width / 2;
977 
978     bool allHidden = true;
979     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
980         if (!child->isTableSection())
981             continue;
982         int sw = toRenderTableSection(child)->outerBorderLeft();
983         if (sw == -1)
984             continue;
985         else
986             allHidden = false;
987         borderWidth = max(borderWidth, sw);
988     }
989     if (allHidden)
990         return 0;
991 
992     return borderWidth;
993 }
994 
outerBorderRight() const995 int RenderTable::outerBorderRight() const
996 {
997     if (!collapseBorders())
998         return 0;
999 
1000     int borderWidth = 0;
1001 
1002     const BorderValue& tb = style()->borderRight();
1003     if (tb.style() == BHIDDEN)
1004         return 0;
1005     if (tb.style() > BHIDDEN)
1006         borderWidth = (tb.width + 1) / 2;
1007 
1008     bool allHidden = true;
1009     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1010         if (!child->isTableSection())
1011             continue;
1012         int sw = toRenderTableSection(child)->outerBorderRight();
1013         if (sw == -1)
1014             continue;
1015         else
1016             allHidden = false;
1017         borderWidth = max(borderWidth, sw);
1018     }
1019     if (allHidden)
1020         return 0;
1021 
1022     return borderWidth;
1023 }
1024 
sectionAbove(const RenderTableSection * section,bool skipEmptySections) const1025 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
1026 {
1027     recalcSectionsIfNeeded();
1028 
1029     if (section == m_head)
1030         return 0;
1031 
1032     RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1033     while (prevSection) {
1034         if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || toRenderTableSection(prevSection)->numRows()))
1035             break;
1036         prevSection = prevSection->previousSibling();
1037     }
1038     if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
1039         prevSection = m_head;
1040     return toRenderTableSection(prevSection);
1041 }
1042 
sectionBelow(const RenderTableSection * section,bool skipEmptySections) const1043 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
1044 {
1045     recalcSectionsIfNeeded();
1046 
1047     if (section == m_foot)
1048         return 0;
1049 
1050     RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1051     while (nextSection) {
1052         if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || toRenderTableSection(nextSection)->numRows()))
1053             break;
1054         nextSection = nextSection->nextSibling();
1055     }
1056     if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
1057         nextSection = m_foot;
1058     return toRenderTableSection(nextSection);
1059 }
1060 
cellAbove(const RenderTableCell * cell) const1061 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1062 {
1063     recalcSectionsIfNeeded();
1064 
1065     // Find the section and row to look in
1066     int r = cell->row();
1067     RenderTableSection* section = 0;
1068     int rAbove = 0;
1069     if (r > 0) {
1070         // cell is not in the first row, so use the above row in its own section
1071         section = cell->section();
1072         rAbove = r - 1;
1073     } else {
1074         section = sectionAbove(cell->section(), true);
1075         if (section)
1076             rAbove = section->numRows() - 1;
1077     }
1078 
1079     // Look up the cell in the section's grid, which requires effective col index
1080     if (section) {
1081         int effCol = colToEffCol(cell->col());
1082         RenderTableSection::CellStruct aboveCell;
1083         // If we hit a span back up to a real cell.
1084         do {
1085             aboveCell = section->cellAt(rAbove, effCol);
1086             effCol--;
1087         } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
1088         return aboveCell.cell;
1089     } else
1090         return 0;
1091 }
1092 
cellBelow(const RenderTableCell * cell) const1093 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1094 {
1095     recalcSectionsIfNeeded();
1096 
1097     // Find the section and row to look in
1098     int r = cell->row() + cell->rowSpan() - 1;
1099     RenderTableSection* section = 0;
1100     int rBelow = 0;
1101     if (r < cell->section()->numRows() - 1) {
1102         // The cell is not in the last row, so use the next row in the section.
1103         section = cell->section();
1104         rBelow = r + 1;
1105     } else {
1106         section = sectionBelow(cell->section(), true);
1107         if (section)
1108             rBelow = 0;
1109     }
1110 
1111     // Look up the cell in the section's grid, which requires effective col index
1112     if (section) {
1113         int effCol = colToEffCol(cell->col());
1114         RenderTableSection::CellStruct belowCell;
1115         // If we hit a colspan back up to a real cell.
1116         do {
1117             belowCell = section->cellAt(rBelow, effCol);
1118             effCol--;
1119         } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
1120         return belowCell.cell;
1121     } else
1122         return 0;
1123 }
1124 
cellBefore(const RenderTableCell * cell) const1125 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1126 {
1127     recalcSectionsIfNeeded();
1128 
1129     RenderTableSection* section = cell->section();
1130     int effCol = colToEffCol(cell->col());
1131     if (!effCol)
1132         return 0;
1133 
1134     // If we hit a colspan back up to a real cell.
1135     RenderTableSection::CellStruct prevCell;
1136     do {
1137         prevCell = section->cellAt(cell->row(), effCol - 1);
1138         effCol--;
1139     } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
1140     return prevCell.cell;
1141 }
1142 
cellAfter(const RenderTableCell * cell) const1143 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1144 {
1145     recalcSectionsIfNeeded();
1146 
1147     int effCol = colToEffCol(cell->col() + cell->colSpan());
1148     if (effCol >= numEffCols())
1149         return 0;
1150     return cell->section()->cellAt(cell->row(), effCol).cell;
1151 }
1152 
firstLineBlock() const1153 RenderBlock* RenderTable::firstLineBlock() const
1154 {
1155     return 0;
1156 }
1157 
updateFirstLetter()1158 void RenderTable::updateFirstLetter()
1159 {
1160 }
1161 
firstLineBoxBaseline() const1162 int RenderTable::firstLineBoxBaseline() const
1163 {
1164     RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
1165     if (firstNonEmptySection && !firstNonEmptySection->numRows())
1166         firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
1167 
1168     if (!firstNonEmptySection)
1169         return -1;
1170 
1171     return firstNonEmptySection->y() + firstNonEmptySection->firstLineBoxBaseline();
1172 }
1173 
overflowClipRect(int tx,int ty)1174 IntRect RenderTable::overflowClipRect(int tx, int ty)
1175 {
1176     IntRect rect = RenderBlock::overflowClipRect(tx, ty);
1177 
1178     // If we have a caption, expand the clip to include the caption.
1179     // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1180     // for real until captions have been re-written.
1181     // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1182     // supported.  When we actually support left/right and stop mapping them to top/bottom,
1183     // we might have to hack this code first (depending on what order we do these bug fixes in).
1184     if (m_caption) {
1185         rect.setHeight(height());
1186         rect.setY(ty);
1187     }
1188 
1189     return rect;
1190 }
1191 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction action)1192 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
1193 {
1194     tx += x();
1195     ty += y();
1196 
1197     // Check kids first.
1198     if (!hasOverflowClip() || overflowClipRect(tx, ty).contains(xPos, yPos)) {
1199         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1200             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) &&
1201                 child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
1202                 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1203                 return true;
1204             }
1205         }
1206     }
1207 
1208     // Check our bounds next.
1209     if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
1210         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1211         return true;
1212     }
1213 
1214     return false;
1215 }
1216 
1217 }
1218