• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3  *           (C) 1997 Torben Weis (weis@kde.org)
4  *           (C) 1998 Waldo Bastian (bastian@kde.org)
5  *           (C) 1999 Lars Knoll (knoll@kde.org)
6  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
8  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 #include "config.h"
27 #include "core/rendering/RenderTable.h"
28 
29 #include "HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/html/HTMLTableElement.h"
32 #include "core/frame/FrameView.h"
33 #include "core/rendering/AutoTableLayout.h"
34 #include "core/rendering/FixedTableLayout.h"
35 #include "core/rendering/GraphicsContextAnnotator.h"
36 #include "core/rendering/HitTestResult.h"
37 #include "core/rendering/LayoutRectRecorder.h"
38 #include "core/rendering/LayoutRepainter.h"
39 #include "core/rendering/RenderLayer.h"
40 #include "core/rendering/RenderTableCaption.h"
41 #include "core/rendering/RenderTableCell.h"
42 #include "core/rendering/RenderTableCol.h"
43 #include "core/rendering/RenderTableSection.h"
44 #include "core/rendering/RenderView.h"
45 #include "core/rendering/SubtreeLayoutScope.h"
46 #include "core/rendering/style/StyleInheritedData.h"
47 #include "platform/graphics/GraphicsContextStateSaver.h"
48 
49 using namespace std;
50 
51 namespace WebCore {
52 
53 using namespace HTMLNames;
54 
RenderTable(Element * element)55 RenderTable::RenderTable(Element* element)
56     : RenderBlock(element)
57     , m_head(0)
58     , m_foot(0)
59     , m_firstBody(0)
60     , m_currentBorder(0)
61     , m_collapsedBordersValid(false)
62     , m_hasColElements(false)
63     , m_needsSectionRecalc(false)
64     , m_columnLogicalWidthChanged(false)
65     , m_columnRenderersValid(false)
66     , m_hSpacing(0)
67     , m_vSpacing(0)
68     , m_borderStart(0)
69     , m_borderEnd(0)
70 {
71     setChildrenInline(false);
72     m_columnPos.fill(0, 1);
73 
74 }
75 
~RenderTable()76 RenderTable::~RenderTable()
77 {
78 }
79 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)80 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
81 {
82     RenderBlock::styleDidChange(diff, oldStyle);
83     propagateStyleToAnonymousChildren();
84 
85     ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
86 
87     // In the collapsed border model, there is no cell spacing.
88     m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
89     m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
90     m_columnPos[0] = m_hSpacing;
91 
92     if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
93         if (m_tableLayout)
94             m_tableLayout->willChangeTableLayout();
95 
96         // According to the CSS2 spec, you only use fixed table layout if an
97         // explicit width is specified on the table.  Auto width implies auto table layout.
98         if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto())
99             m_tableLayout = adoptPtr(new FixedTableLayout(this));
100         else
101             m_tableLayout = adoptPtr(new AutoTableLayout(this));
102     }
103 
104     // If border was changed, invalidate collapsed borders cache.
105     if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
106         invalidateCollapsedBorders();
107 }
108 
resetSectionPointerIfNotBefore(RenderTableSection * & ptr,RenderObject * before)109 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
110 {
111     if (!before || !ptr)
112         return;
113     RenderObject* o = before->previousSibling();
114     while (o && o != ptr)
115         o = o->previousSibling();
116     if (!o)
117         ptr = 0;
118 }
119 
addChild(RenderObject * child,RenderObject * beforeChild)120 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
121 {
122     bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
123 
124     if (child->isTableCaption())
125         wrapInAnonymousSection = false;
126     else if (child->isRenderTableCol()) {
127         m_hasColElements = true;
128         wrapInAnonymousSection = false;
129     } else if (child->isTableSection()) {
130         switch (child->style()->display()) {
131             case TABLE_HEADER_GROUP:
132                 resetSectionPointerIfNotBefore(m_head, beforeChild);
133                 if (!m_head) {
134                     m_head = toRenderTableSection(child);
135                 } else {
136                     resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
137                     if (!m_firstBody)
138                         m_firstBody = toRenderTableSection(child);
139                 }
140                 wrapInAnonymousSection = false;
141                 break;
142             case TABLE_FOOTER_GROUP:
143                 resetSectionPointerIfNotBefore(m_foot, beforeChild);
144                 if (!m_foot) {
145                     m_foot = toRenderTableSection(child);
146                     wrapInAnonymousSection = false;
147                     break;
148                 }
149                 // Fall through.
150             case TABLE_ROW_GROUP:
151                 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
152                 if (!m_firstBody)
153                     m_firstBody = toRenderTableSection(child);
154                 wrapInAnonymousSection = false;
155                 break;
156             default:
157                 ASSERT_NOT_REACHED();
158         }
159     } else if (child->isTableCell() || child->isTableRow())
160         wrapInAnonymousSection = true;
161     else
162         wrapInAnonymousSection = true;
163 
164     if (child->isTableSection())
165         setNeedsSectionRecalc();
166 
167     if (!wrapInAnonymousSection) {
168         if (beforeChild && beforeChild->parent() != this)
169             beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
170 
171         RenderBox::addChild(child, beforeChild);
172         return;
173     }
174 
175     if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
176         lastChild()->addChild(child);
177         return;
178     }
179 
180     if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
181         RenderObject* section = beforeChild->previousSibling();
182         if (section && section->isTableSection() && section->isAnonymous()) {
183             section->addChild(child);
184             return;
185         }
186     }
187 
188     RenderObject* lastBox = beforeChild;
189     while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
190         lastBox = lastBox->parent();
191     if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
192         if (beforeChild == lastBox)
193             beforeChild = lastBox->firstChild();
194         lastBox->addChild(child, beforeChild);
195         return;
196     }
197 
198     if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
199         beforeChild = 0;
200 
201     RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
202     addChild(section, beforeChild);
203     section->addChild(child);
204 }
205 
addCaption(const RenderTableCaption * caption)206 void RenderTable::addCaption(const RenderTableCaption* caption)
207 {
208     ASSERT(m_captions.find(caption) == kNotFound);
209     m_captions.append(const_cast<RenderTableCaption*>(caption));
210 }
211 
removeCaption(const RenderTableCaption * oldCaption)212 void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
213 {
214     size_t index = m_captions.find(oldCaption);
215     ASSERT(index != kNotFound);
216     if (index == kNotFound)
217         return;
218 
219     m_captions.remove(index);
220 }
221 
invalidateCachedColumns()222 void RenderTable::invalidateCachedColumns()
223 {
224     m_columnRenderersValid = false;
225     m_columnRenderers.resize(0);
226 }
227 
addColumn(const RenderTableCol *)228 void RenderTable::addColumn(const RenderTableCol*)
229 {
230     invalidateCachedColumns();
231 }
232 
removeColumn(const RenderTableCol *)233 void RenderTable::removeColumn(const RenderTableCol*)
234 {
235     invalidateCachedColumns();
236     // We don't really need to recompute our sections, but we need to update our
237     // column count and whether we have a column. Currently, we only have one
238     // size-fit-all flag but we may have to consider splitting it.
239     setNeedsSectionRecalc();
240 }
241 
updateLogicalWidth()242 void RenderTable::updateLogicalWidth()
243 {
244     recalcSectionsIfNeeded();
245 
246     if (isOutOfFlowPositioned()) {
247         LogicalExtentComputedValues computedValues;
248         computePositionedLogicalWidth(computedValues);
249         setLogicalWidth(computedValues.m_extent);
250         setLogicalLeft(computedValues.m_position);
251         setMarginStart(computedValues.m_margins.m_start);
252         setMarginEnd(computedValues.m_margins.m_end);
253     }
254 
255     RenderBlock* cb = containingBlock();
256     RenderView* renderView = view();
257 
258     LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
259     bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
260     LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
261 
262     Length styleLogicalWidth = style()->logicalWidth();
263     if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
264         setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
265     else {
266         // Subtract out any fixed margins from our available width for auto width tables.
267         LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
268         LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
269         LayoutUnit marginTotal = marginStart + marginEnd;
270 
271         // Subtract out our margins to get the available content width.
272         LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
273         if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
274             // FIXME: Work with regions someday.
275             availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb), 0);
276         }
277 
278         // Ensure we aren't bigger than our available width.
279         setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
280     }
281 
282     // Ensure we aren't bigger than our max-width style.
283     Length styleMaxLogicalWidth = style()->logicalMaxWidth();
284     if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
285         LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
286         setLogicalWidth(min<int>(logicalWidth(), computedMaxLogicalWidth));
287     }
288 
289     // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as
290     // we ignore it if it means we wouldn't accomodate our content.
291     setLogicalWidth(max<int>(logicalWidth(), minPreferredLogicalWidth()));
292 
293      // Ensure we aren't smaller than our min-width style.
294     Length styleMinLogicalWidth = style()->logicalMinWidth();
295     if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
296         LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
297         setLogicalWidth(max<int>(logicalWidth(), computedMinLogicalWidth));
298     }
299 
300     // Finally, with our true width determined, compute our margins for real.
301     setMarginStart(0);
302     setMarginEnd(0);
303     if (!hasPerpendicularContainingBlock) {
304         LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
305         if (avoidsFloats() && cb->containsFloats())
306             containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday.
307         ComputedMarginValues marginValues;
308         bool hasInvertedDirection =  cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection();
309         computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(),
310             hasInvertedDirection ? marginValues.m_start : marginValues.m_end,
311             hasInvertedDirection ? marginValues.m_end : marginValues.m_start);
312         setMarginStart(marginValues.m_start);
313         setMarginEnd(marginValues.m_end);
314     } else {
315         setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView));
316         setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView));
317     }
318 
319     // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
320     // its own content which doesn't match CSS nor what authors expect.
321     // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
322     // https://code.google.com/p/chromium/issues/detail?id=241198
323     ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt());
324 }
325 
326 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
convertStyleLogicalWidthToComputedWidth(const Length & styleLogicalWidth,LayoutUnit availableWidth)327 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
328 {
329     if (styleLogicalWidth.isIntrinsic())
330         return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
331 
332     // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
333     LayoutUnit borders = 0;
334     bool isCSSTable = !node() || !isHTMLTableElement(node());
335     if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
336         borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
337 
338     return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders;
339 }
340 
convertStyleLogicalHeightToComputedHeight(const Length & styleLogicalHeight)341 LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
342 {
343     LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
344     LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
345     LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter;
346     LayoutUnit computedLogicalHeight = 0;
347     if (styleLogicalHeight.isFixed()) {
348         // HTML tables size as though CSS height includes border/padding, CSS tables do not.
349         LayoutUnit borders = LayoutUnit();
350         // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
351         if ((node() && isHTMLTableElement(node())) || style()->boxSizing() == BORDER_BOX) {
352             borders = borderAndPadding;
353         }
354         computedLogicalHeight = styleLogicalHeight.value() - borders;
355     } else if (styleLogicalHeight.isPercent())
356         computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
357     else if (styleLogicalHeight.isViewportPercentage())
358         computedLogicalHeight = minimumValueForLength(styleLogicalHeight, 0, view());
359     else if (styleLogicalHeight.isIntrinsic())
360         computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding);
361     else
362         ASSERT_NOT_REACHED();
363     return max<LayoutUnit>(0, computedLogicalHeight);
364 }
365 
layoutCaption(RenderTableCaption * caption)366 void RenderTable::layoutCaption(RenderTableCaption* caption)
367 {
368     LayoutRect captionRect(caption->frameRect());
369 
370     if (caption->needsLayout()) {
371         // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
372         // so that it does not mistakenly think any floats in the previous caption intrude into it.
373         caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight()));
374         // If RenderTableCaption ever gets a layout() function, use it here.
375         caption->layoutIfNeeded();
376     }
377     // Apply the margins to the location now that they are definitely available from layout
378     caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight()));
379 
380     if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
381         caption->repaintDuringLayoutIfMoved(captionRect);
382 
383     setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption));
384 }
385 
distributeExtraLogicalHeight(int extraLogicalHeight)386 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
387 {
388     if (extraLogicalHeight <= 0)
389         return;
390 
391     // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
392     if (RenderTableSection* section = firstBody())
393         extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
394 
395     // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
396     // However our current distribution algorithm does not round properly and thus we can have some remaining height.
397     // ASSERT(!topSection() || !extraLogicalHeight);
398 }
399 
simplifiedNormalFlowLayout()400 void RenderTable::simplifiedNormalFlowLayout()
401 {
402     for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
403         section->layoutIfNeeded();
404         section->computeOverflowFromCells();
405     }
406 }
407 
layout()408 void RenderTable::layout()
409 {
410     ASSERT(needsLayout());
411 
412     LayoutRectRecorder recorder(*this);
413 
414     if (simplifiedLayout())
415         return;
416 
417     recalcSectionsIfNeeded();
418     // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
419     // to call this before we call borderStart/borderEnd to avoid getting a stale value.
420     recalcBordersInRowDirection();
421 
422     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
423     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
424 
425     setLogicalHeight(0);
426 
427     LayoutUnit oldLogicalWidth = logicalWidth();
428     updateLogicalWidth();
429 
430     SubtreeLayoutScope layouter(this);
431 
432     if (logicalWidth() != oldLogicalWidth) {
433         for (unsigned i = 0; i < m_captions.size(); i++)
434             layouter.setNeedsLayout(m_captions[i]);
435     }
436     // FIXME: The optimisation below doesn't work since the internal table
437     // layout could have changed.  we need to add a flag to the table
438     // layout that tells us if something has changed in the min max
439     // calculations to do it correctly.
440 //     if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
441     m_tableLayout->layout();
442 
443     LayoutUnit totalSectionLogicalHeight = 0;
444     LayoutUnit oldTableLogicalTop = 0;
445     for (unsigned i = 0; i < m_captions.size(); i++)
446         oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
447 
448     bool collapsing = collapseBorders();
449 
450     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
451         if (child->isTableSection()) {
452             RenderTableSection* section = toRenderTableSection(child);
453             if (m_columnLogicalWidthChanged)
454                 layouter.setChildNeedsLayout(section);
455             section->layoutIfNeeded();
456             totalSectionLogicalHeight += section->calcRowLogicalHeight();
457             if (collapsing)
458                 section->recalcOuterBorder();
459             ASSERT(!section->needsLayout());
460         } else if (child->isRenderTableCol()) {
461             child->layoutIfNeeded();
462             ASSERT(!child->needsLayout());
463         } else {
464             // FIXME: We should never have other type of children (they should be wrapped in an
465             // anonymous table section) but our code is too crazy and this can happen in practice.
466             // Until this is fixed, let's make sure we don't leave non laid out children in the tree.
467             child->layoutIfNeeded();
468         }
469     }
470 
471     // If any table section moved vertically, we will just repaint everything from that
472     // section down (it is quite unlikely that any of the following sections
473     // did not shift).
474     bool sectionMoved = false;
475     LayoutUnit movedSectionLogicalTop = 0;
476 
477     // FIXME: Collapse caption margin.
478     if (!m_captions.isEmpty()) {
479         for (unsigned i = 0; i < m_captions.size(); i++) {
480             if (m_captions[i]->style()->captionSide() == CAPBOTTOM)
481                 continue;
482             layoutCaption(m_captions[i]);
483         }
484         if (logicalHeight() != oldTableLogicalTop) {
485             sectionMoved = true;
486             movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
487         }
488     }
489 
490     LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore());
491     LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter());
492 
493     setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
494 
495     if (!isOutOfFlowPositioned())
496         updateLogicalHeight();
497 
498     LayoutUnit computedLogicalHeight = 0;
499 
500     Length logicalHeightLength = style()->logicalHeight();
501     if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive()))
502         computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength);
503 
504     Length logicalMaxHeightLength = style()->logicalMaxHeight();
505     if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) {
506         LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength);
507         computedLogicalHeight = min(computedLogicalHeight, computedMaxLogicalHeight);
508     }
509 
510     Length logicalMinHeightLength = style()->logicalMinHeight();
511     if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) {
512         LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength);
513         computedLogicalHeight = max(computedLogicalHeight, computedMinLogicalHeight);
514     }
515 
516     distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
517 
518     for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
519         section->layoutRows();
520 
521     if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) {
522         // Completely empty tables (with no sections or anything) should at least honor specified height
523         // in strict mode.
524         setLogicalHeight(logicalHeight() + computedLogicalHeight);
525     }
526 
527     LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
528     if (!collapsing)
529         sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
530 
531     // position the table sections
532     RenderTableSection* section = topSection();
533     while (section) {
534         if (!sectionMoved && section->logicalTop() != logicalHeight()) {
535             sectionMoved = true;
536             movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x());
537         }
538         section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
539 
540         setLogicalHeight(logicalHeight() + section->logicalHeight());
541         section = sectionBelow(section);
542     }
543 
544     setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
545 
546     for (unsigned i = 0; i < m_captions.size(); i++) {
547         if (m_captions[i]->style()->captionSide() != CAPBOTTOM)
548             continue;
549         layoutCaption(m_captions[i]);
550     }
551 
552     if (isOutOfFlowPositioned())
553         updateLogicalHeight();
554 
555     // table can be containing block of positioned elements.
556     // FIXME: Only pass true if width or height changed.
557     layoutPositionedObjects(true);
558 
559     updateLayerTransform();
560 
561     // Layout was changed, so probably borders too.
562     invalidateCollapsedBorders();
563 
564     computeOverflow(clientLogicalBottom());
565 
566     statePusher.pop();
567 
568     if (view()->layoutState()->pageLogicalHeight())
569         setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
570 
571     bool didFullRepaint = repainter.repaintAfterLayout();
572     // Repaint with our new bounds if they are different from our old bounds.
573     if (!didFullRepaint && sectionMoved) {
574         if (style()->isHorizontalWritingMode())
575             repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop));
576         else
577             repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height()));
578     }
579 
580     m_columnLogicalWidthChanged = false;
581     clearNeedsLayout();
582 }
583 
584 // Collect all the unique border values that we want to paint in a sorted list.
recalcCollapsedBorders()585 void RenderTable::recalcCollapsedBorders()
586 {
587     if (m_collapsedBordersValid)
588         return;
589     m_collapsedBordersValid = true;
590     m_collapsedBorders.clear();
591     for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
592         if (!section->isTableSection())
593             continue;
594         for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) {
595             if (!row->isTableRow())
596                 continue;
597             for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
598                 if (!cell->isTableCell())
599                     continue;
600                 ASSERT(toRenderTableCell(cell)->table() == this);
601                 toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders);
602             }
603         }
604     }
605     RenderTableCell::sortBorderValues(m_collapsedBorders);
606 }
607 
608 
addOverflowFromChildren()609 void RenderTable::addOverflowFromChildren()
610 {
611     // Add overflow from borders.
612     // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
613     // descendant objects, but since tables don't support overflow:auto, this works out fine.
614     if (collapseBorders()) {
615         int rightBorderOverflow = width() + outerBorderRight() - borderRight();
616         int leftBorderOverflow = borderLeft() - outerBorderLeft();
617         int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
618         int topBorderOverflow = borderTop() - outerBorderTop();
619         IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
620         if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
621             addLayoutOverflow(borderOverflowRect);
622             addVisualOverflow(borderOverflowRect);
623         }
624     }
625 
626     // Add overflow from our caption.
627     for (unsigned i = 0; i < m_captions.size(); i++)
628         addOverflowFromChild(m_captions[i]);
629 
630     // Add overflow from our sections.
631     for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
632         addOverflowFromChild(section);
633 }
634 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)635 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
636 {
637     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
638 
639     LayoutPoint adjustedPaintOffset = paintOffset + location();
640 
641     PaintPhase paintPhase = paintInfo.phase;
642 
643     if (!isRoot()) {
644         LayoutRect overflowBox = visualOverflowRect();
645         flipForWritingMode(overflowBox);
646         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
647         overflowBox.moveBy(adjustedPaintOffset);
648         if (!overflowBox.intersects(paintInfo.rect))
649             return;
650     }
651 
652     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
653     paintObject(paintInfo, adjustedPaintOffset);
654     if (pushedClip)
655         popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
656 }
657 
paintObject(PaintInfo & paintInfo,const LayoutPoint & paintOffset)658 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
659 {
660     PaintPhase paintPhase = paintInfo.phase;
661     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
662         paintBoxDecorations(paintInfo, paintOffset);
663 
664     if (paintPhase == PaintPhaseMask) {
665         paintMask(paintInfo, paintOffset);
666         return;
667     }
668 
669     // We're done.  We don't bother painting any children.
670     if (paintPhase == PaintPhaseBlockBackground)
671         return;
672 
673     // We don't paint our own background, but we do let the kids paint their backgrounds.
674     if (paintPhase == PaintPhaseChildBlockBackgrounds)
675         paintPhase = PaintPhaseChildBlockBackground;
676 
677     PaintInfo info(paintInfo);
678     info.phase = paintPhase;
679     info.updatePaintingRootForChildren(this);
680 
681     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
682         if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
683             LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
684             child->paint(info, childPoint);
685         }
686     }
687 
688     if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
689         recalcCollapsedBorders();
690         // Using our cached sorted styles, we then do individual passes,
691         // painting each style of border from lowest precedence to highest precedence.
692         info.phase = PaintPhaseCollapsedTableBorders;
693         size_t count = m_collapsedBorders.size();
694         for (size_t i = 0; i < count; ++i) {
695             m_currentBorder = &m_collapsedBorders[i];
696             for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
697                 LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
698                 section->paint(info, childPoint);
699             }
700         }
701         m_currentBorder = 0;
702     }
703 
704     // Paint outline.
705     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
706         paintOutline(paintInfo, LayoutRect(paintOffset, size()));
707 }
708 
subtractCaptionRect(LayoutRect & rect) const709 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
710 {
711     for (unsigned i = 0; i < m_captions.size(); i++) {
712         LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
713         bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
714         if (style()->isHorizontalWritingMode()) {
715             rect.setHeight(rect.height() - captionLogicalHeight);
716             if (captionIsBefore)
717                 rect.move(0, captionLogicalHeight);
718         } else {
719             rect.setWidth(rect.width() - captionLogicalHeight);
720             if (captionIsBefore)
721                 rect.move(captionLogicalHeight, 0);
722         }
723     }
724 }
725 
paintBoxDecorations(PaintInfo & paintInfo,const LayoutPoint & paintOffset)726 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
727 {
728     if (!paintInfo.shouldPaintWithinRoot(this))
729         return;
730 
731     LayoutRect rect(paintOffset, size());
732     subtractCaptionRect(rect);
733     paintBoxDecorationsWithRect(paintInfo, paintOffset, rect);
734 }
735 
paintMask(PaintInfo & paintInfo,const LayoutPoint & paintOffset)736 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
737 {
738     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
739         return;
740 
741     LayoutRect rect(paintOffset, size());
742     subtractCaptionRect(rect);
743 
744     paintMaskImages(paintInfo, rect);
745 }
746 
computeIntrinsicLogicalWidths(LayoutUnit & minWidth,LayoutUnit & maxWidth) const747 void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
748 {
749     recalcSectionsIfNeeded();
750     // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
751     // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
752     // of reading out stale values.
753     const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
754     // FIXME: Restructure the table layout code so that we can make this method const.
755     const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
756 
757     // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
758 }
759 
computePreferredLogicalWidths()760 void RenderTable::computePreferredLogicalWidths()
761 {
762     ASSERT(preferredLogicalWidthsDirty());
763 
764     computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
765 
766     int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
767     m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
768     m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
769 
770     m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
771 
772     for (unsigned i = 0; i < m_captions.size(); i++)
773         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
774 
775     RenderStyle* styleToUse = style();
776     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
777     if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
778         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
779         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
780     }
781 
782     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
783     if (styleToUse->logicalMaxWidth().isFixed()) {
784         // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'.
785         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
786         m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
787     }
788 
789     // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
790     // so a bunch of tests break doing this naively.
791     clearPreferredLogicalWidthsDirty();
792 }
793 
topNonEmptySection() const794 RenderTableSection* RenderTable::topNonEmptySection() const
795 {
796     RenderTableSection* section = topSection();
797     if (section && !section->numRows())
798         section = sectionBelow(section, SkipEmptySections);
799     return section;
800 }
801 
splitColumn(unsigned position,unsigned firstSpan)802 void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
803 {
804     // We split the column at "position", taking "firstSpan" cells from the span.
805     ASSERT(m_columns[position].span > firstSpan);
806     m_columns.insert(position, ColumnStruct(firstSpan));
807     m_columns[position + 1].span -= firstSpan;
808 
809     // Propagate the change in our columns representation to the sections that don't need
810     // cell recalc. If they do, they will be synced up directly with m_columns later.
811     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
812         if (!child->isTableSection())
813             continue;
814 
815         RenderTableSection* section = toRenderTableSection(child);
816         if (section->needsCellRecalc())
817             continue;
818 
819         section->splitColumn(position, firstSpan);
820     }
821 
822     m_columnPos.grow(numEffCols() + 1);
823 }
824 
appendColumn(unsigned span)825 void RenderTable::appendColumn(unsigned span)
826 {
827     unsigned newColumnIndex = m_columns.size();
828     m_columns.append(ColumnStruct(span));
829 
830     // Propagate the change in our columns representation to the sections that don't need
831     // cell recalc. If they do, they will be synced up directly with m_columns later.
832     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
833         if (!child->isTableSection())
834             continue;
835 
836         RenderTableSection* section = toRenderTableSection(child);
837         if (section->needsCellRecalc())
838             continue;
839 
840         section->appendColumn(newColumnIndex);
841     }
842 
843     m_columnPos.grow(numEffCols() + 1);
844 }
845 
firstColumn() const846 RenderTableCol* RenderTable::firstColumn() const
847 {
848     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
849         if (child->isRenderTableCol())
850             return toRenderTableCol(child);
851     }
852 
853     return 0;
854 }
855 
updateColumnCache() const856 void RenderTable::updateColumnCache() const
857 {
858     ASSERT(m_hasColElements);
859     ASSERT(m_columnRenderers.isEmpty());
860     ASSERT(!m_columnRenderersValid);
861 
862     for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
863         if (columnRenderer->isTableColumnGroupWithColumnChildren())
864             continue;
865         m_columnRenderers.append(columnRenderer);
866     }
867     m_columnRenderersValid = true;
868 }
869 
slowColElement(unsigned col,bool * startEdge,bool * endEdge) const870 RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
871 {
872     ASSERT(m_hasColElements);
873 
874     if (!m_columnRenderersValid)
875         updateColumnCache();
876 
877     unsigned columnCount = 0;
878     for (unsigned i = 0; i < m_columnRenderers.size(); i++) {
879         RenderTableCol* columnRenderer = m_columnRenderers[i];
880         unsigned span = columnRenderer->span();
881         unsigned startCol = columnCount;
882         ASSERT(span >= 1);
883         unsigned endCol = columnCount + span - 1;
884         columnCount += span;
885         if (columnCount > col) {
886             if (startEdge)
887                 *startEdge = startCol == col;
888             if (endEdge)
889                 *endEdge = endCol == col;
890             return columnRenderer;
891         }
892     }
893     return 0;
894 }
895 
recalcSections() const896 void RenderTable::recalcSections() const
897 {
898     ASSERT(m_needsSectionRecalc);
899 
900     m_head = 0;
901     m_foot = 0;
902     m_firstBody = 0;
903     m_hasColElements = false;
904 
905     // We need to get valid pointers to caption, head, foot and first body again
906     RenderObject* nextSibling;
907     for (RenderObject* child = firstChild(); child; child = nextSibling) {
908         nextSibling = child->nextSibling();
909         switch (child->style()->display()) {
910         case TABLE_COLUMN:
911         case TABLE_COLUMN_GROUP:
912             m_hasColElements = true;
913             break;
914         case TABLE_HEADER_GROUP:
915             if (child->isTableSection()) {
916                 RenderTableSection* section = toRenderTableSection(child);
917                 if (!m_head)
918                     m_head = section;
919                 else if (!m_firstBody)
920                     m_firstBody = section;
921                 section->recalcCellsIfNeeded();
922             }
923             break;
924         case TABLE_FOOTER_GROUP:
925             if (child->isTableSection()) {
926                 RenderTableSection* section = toRenderTableSection(child);
927                 if (!m_foot)
928                     m_foot = section;
929                 else if (!m_firstBody)
930                     m_firstBody = section;
931                 section->recalcCellsIfNeeded();
932             }
933             break;
934         case TABLE_ROW_GROUP:
935             if (child->isTableSection()) {
936                 RenderTableSection* section = toRenderTableSection(child);
937                 if (!m_firstBody)
938                     m_firstBody = section;
939                 section->recalcCellsIfNeeded();
940             }
941             break;
942         default:
943             break;
944         }
945     }
946 
947     // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
948     unsigned maxCols = 0;
949     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
950         if (child->isTableSection()) {
951             RenderTableSection* section = toRenderTableSection(child);
952             unsigned sectionCols = section->numColumns();
953             if (sectionCols > maxCols)
954                 maxCols = sectionCols;
955         }
956     }
957 
958     m_columns.resize(maxCols);
959     m_columnPos.resize(maxCols + 1);
960 
961     ASSERT(selfNeedsLayout());
962 
963     m_needsSectionRecalc = false;
964 }
965 
calcBorderStart() const966 int RenderTable::calcBorderStart() const
967 {
968     if (!collapseBorders())
969         return RenderBlock::borderStart();
970 
971     // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
972     if (!numEffCols())
973         return 0;
974 
975     unsigned borderWidth = 0;
976 
977     const BorderValue& tableStartBorder = style()->borderStart();
978     if (tableStartBorder.style() == BHIDDEN)
979         return 0;
980     if (tableStartBorder.style() > BHIDDEN)
981         borderWidth = tableStartBorder.width();
982 
983     if (RenderTableCol* column = colElement(0)) {
984         // FIXME: We don't account for direction on columns and column groups.
985         const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
986         if (columnAdjoiningBorder.style() == BHIDDEN)
987             return 0;
988         if (columnAdjoiningBorder.style() > BHIDDEN)
989             borderWidth = max(borderWidth, columnAdjoiningBorder.width());
990         // FIXME: This logic doesn't properly account for the first column in the first column-group case.
991     }
992 
993     if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
994         const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
995         if (sectionAdjoiningBorder.style() == BHIDDEN)
996             return 0;
997 
998         if (sectionAdjoiningBorder.style() > BHIDDEN)
999             borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1000 
1001         if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
1002             // FIXME: Make this work with perpendicular and flipped cells.
1003             const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
1004             if (startCellAdjoiningBorder.style() == BHIDDEN)
1005                 return 0;
1006 
1007             const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
1008             if (firstRowAdjoiningBorder.style() == BHIDDEN)
1009                 return 0;
1010 
1011             if (startCellAdjoiningBorder.style() > BHIDDEN)
1012                 borderWidth = max(borderWidth, startCellAdjoiningBorder.width());
1013             if (firstRowAdjoiningBorder.style() > BHIDDEN)
1014                 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1015         }
1016     }
1017     return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1018 }
1019 
calcBorderEnd() const1020 int RenderTable::calcBorderEnd() const
1021 {
1022     if (!collapseBorders())
1023         return RenderBlock::borderEnd();
1024 
1025     // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
1026     if (!numEffCols())
1027         return 0;
1028 
1029     unsigned borderWidth = 0;
1030 
1031     const BorderValue& tableEndBorder = style()->borderEnd();
1032     if (tableEndBorder.style() == BHIDDEN)
1033         return 0;
1034     if (tableEndBorder.style() > BHIDDEN)
1035         borderWidth = tableEndBorder.width();
1036 
1037     unsigned endColumn = numEffCols() - 1;
1038     if (RenderTableCol* column = colElement(endColumn)) {
1039         // FIXME: We don't account for direction on columns and column groups.
1040         const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
1041         if (columnAdjoiningBorder.style() == BHIDDEN)
1042             return 0;
1043         if (columnAdjoiningBorder.style() > BHIDDEN)
1044             borderWidth = max(borderWidth, columnAdjoiningBorder.width());
1045         // FIXME: This logic doesn't properly account for the last column in the last column-group case.
1046     }
1047 
1048     if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1049         const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
1050         if (sectionAdjoiningBorder.style() == BHIDDEN)
1051             return 0;
1052 
1053         if (sectionAdjoiningBorder.style() > BHIDDEN)
1054             borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1055 
1056         if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
1057             // FIXME: Make this work with perpendicular and flipped cells.
1058             const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
1059             if (endCellAdjoiningBorder.style() == BHIDDEN)
1060                 return 0;
1061 
1062             const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
1063             if (firstRowAdjoiningBorder.style() == BHIDDEN)
1064                 return 0;
1065 
1066             if (endCellAdjoiningBorder.style() > BHIDDEN)
1067                 borderWidth = max(borderWidth, endCellAdjoiningBorder.width());
1068             if (firstRowAdjoiningBorder.style() > BHIDDEN)
1069                 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1070         }
1071     }
1072     return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1073 }
1074 
recalcBordersInRowDirection()1075 void RenderTable::recalcBordersInRowDirection()
1076 {
1077     // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1078     m_borderStart = calcBorderStart();
1079     m_borderEnd = calcBorderEnd();
1080 }
1081 
borderBefore() const1082 int RenderTable::borderBefore() const
1083 {
1084     if (collapseBorders()) {
1085         recalcSectionsIfNeeded();
1086         return outerBorderBefore();
1087     }
1088     return RenderBlock::borderBefore();
1089 }
1090 
borderAfter() const1091 int RenderTable::borderAfter() const
1092 {
1093     if (collapseBorders()) {
1094         recalcSectionsIfNeeded();
1095         return outerBorderAfter();
1096     }
1097     return RenderBlock::borderAfter();
1098 }
1099 
outerBorderBefore() const1100 int RenderTable::outerBorderBefore() const
1101 {
1102     if (!collapseBorders())
1103         return 0;
1104     int borderWidth = 0;
1105     if (RenderTableSection* topSection = this->topSection()) {
1106         borderWidth = topSection->outerBorderBefore();
1107         if (borderWidth < 0)
1108             return 0;   // Overridden by hidden
1109     }
1110     const BorderValue& tb = style()->borderBefore();
1111     if (tb.style() == BHIDDEN)
1112         return 0;
1113     if (tb.style() > BHIDDEN)
1114         borderWidth = max<int>(borderWidth, tb.width() / 2);
1115     return borderWidth;
1116 }
1117 
outerBorderAfter() const1118 int RenderTable::outerBorderAfter() const
1119 {
1120     if (!collapseBorders())
1121         return 0;
1122     int borderWidth = 0;
1123 
1124     if (RenderTableSection* section = bottomSection()) {
1125         borderWidth = section->outerBorderAfter();
1126         if (borderWidth < 0)
1127             return 0; // Overridden by hidden
1128     }
1129     const BorderValue& tb = style()->borderAfter();
1130     if (tb.style() == BHIDDEN)
1131         return 0;
1132     if (tb.style() > BHIDDEN)
1133         borderWidth = max<int>(borderWidth, (tb.width() + 1) / 2);
1134     return borderWidth;
1135 }
1136 
outerBorderStart() const1137 int RenderTable::outerBorderStart() const
1138 {
1139     if (!collapseBorders())
1140         return 0;
1141 
1142     int borderWidth = 0;
1143 
1144     const BorderValue& tb = style()->borderStart();
1145     if (tb.style() == BHIDDEN)
1146         return 0;
1147     if (tb.style() > BHIDDEN)
1148         borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1149 
1150     bool allHidden = true;
1151     for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1152         int sw = section->outerBorderStart();
1153         if (sw < 0)
1154             continue;
1155         allHidden = false;
1156         borderWidth = max(borderWidth, sw);
1157     }
1158     if (allHidden)
1159         return 0;
1160 
1161     return borderWidth;
1162 }
1163 
outerBorderEnd() const1164 int RenderTable::outerBorderEnd() const
1165 {
1166     if (!collapseBorders())
1167         return 0;
1168 
1169     int borderWidth = 0;
1170 
1171     const BorderValue& tb = style()->borderEnd();
1172     if (tb.style() == BHIDDEN)
1173         return 0;
1174     if (tb.style() > BHIDDEN)
1175         borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1176 
1177     bool allHidden = true;
1178     for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1179         int sw = section->outerBorderEnd();
1180         if (sw < 0)
1181             continue;
1182         allHidden = false;
1183         borderWidth = max(borderWidth, sw);
1184     }
1185     if (allHidden)
1186         return 0;
1187 
1188     return borderWidth;
1189 }
1190 
sectionAbove(const RenderTableSection * section,SkipEmptySectionsValue skipEmptySections) const1191 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1192 {
1193     recalcSectionsIfNeeded();
1194 
1195     if (section == m_head)
1196         return 0;
1197 
1198     RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1199     while (prevSection) {
1200         if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1201             break;
1202         prevSection = prevSection->previousSibling();
1203     }
1204     if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1205         prevSection = m_head;
1206     return toRenderTableSection(prevSection);
1207 }
1208 
sectionBelow(const RenderTableSection * section,SkipEmptySectionsValue skipEmptySections) const1209 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1210 {
1211     recalcSectionsIfNeeded();
1212 
1213     if (section == m_foot)
1214         return 0;
1215 
1216     RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1217     while (nextSection) {
1218         if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections  == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1219             break;
1220         nextSection = nextSection->nextSibling();
1221     }
1222     if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1223         nextSection = m_foot;
1224     return toRenderTableSection(nextSection);
1225 }
1226 
bottomSection() const1227 RenderTableSection* RenderTable::bottomSection() const
1228 {
1229     recalcSectionsIfNeeded();
1230 
1231     if (m_foot)
1232         return m_foot;
1233 
1234     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1235         if (child->isTableSection())
1236             return toRenderTableSection(child);
1237     }
1238 
1239     return 0;
1240 }
1241 
cellAbove(const RenderTableCell * cell) const1242 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1243 {
1244     recalcSectionsIfNeeded();
1245 
1246     // Find the section and row to look in
1247     unsigned r = cell->rowIndex();
1248     RenderTableSection* section = 0;
1249     unsigned rAbove = 0;
1250     if (r > 0) {
1251         // cell is not in the first row, so use the above row in its own section
1252         section = cell->section();
1253         rAbove = r - 1;
1254     } else {
1255         section = sectionAbove(cell->section(), SkipEmptySections);
1256         if (section) {
1257             ASSERT(section->numRows());
1258             rAbove = section->numRows() - 1;
1259         }
1260     }
1261 
1262     // Look up the cell in the section's grid, which requires effective col index
1263     if (section) {
1264         unsigned effCol = colToEffCol(cell->col());
1265         RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1266         return aboveCell.primaryCell();
1267     } else
1268         return 0;
1269 }
1270 
cellBelow(const RenderTableCell * cell) const1271 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1272 {
1273     recalcSectionsIfNeeded();
1274 
1275     // Find the section and row to look in
1276     unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1277     RenderTableSection* section = 0;
1278     unsigned rBelow = 0;
1279     if (r < cell->section()->numRows() - 1) {
1280         // The cell is not in the last row, so use the next row in the section.
1281         section = cell->section();
1282         rBelow = r + 1;
1283     } else {
1284         section = sectionBelow(cell->section(), SkipEmptySections);
1285         if (section)
1286             rBelow = 0;
1287     }
1288 
1289     // Look up the cell in the section's grid, which requires effective col index
1290     if (section) {
1291         unsigned effCol = colToEffCol(cell->col());
1292         RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1293         return belowCell.primaryCell();
1294     } else
1295         return 0;
1296 }
1297 
cellBefore(const RenderTableCell * cell) const1298 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1299 {
1300     recalcSectionsIfNeeded();
1301 
1302     RenderTableSection* section = cell->section();
1303     unsigned effCol = colToEffCol(cell->col());
1304     if (!effCol)
1305         return 0;
1306 
1307     // If we hit a colspan back up to a real cell.
1308     RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1309     return prevCell.primaryCell();
1310 }
1311 
cellAfter(const RenderTableCell * cell) const1312 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1313 {
1314     recalcSectionsIfNeeded();
1315 
1316     unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1317     if (effCol >= numEffCols())
1318         return 0;
1319     return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1320 }
1321 
firstLineBlock() const1322 RenderBlock* RenderTable::firstLineBlock() const
1323 {
1324     return 0;
1325 }
1326 
updateFirstLetter()1327 void RenderTable::updateFirstLetter()
1328 {
1329 }
1330 
baselinePosition(FontBaseline baselineType,bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const1331 int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1332 {
1333     ASSERT(linePositionMode == PositionOnContainingLine);
1334     LayoutUnit baseline = firstLineBoxBaseline();
1335     if (baseline != -1)
1336         return baseline;
1337 
1338     return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
1339 }
1340 
inlineBlockBaseline(LineDirectionMode) const1341 int RenderTable::inlineBlockBaseline(LineDirectionMode) const
1342 {
1343     // Tables are skipped when computing an inline-block's baseline.
1344     return -1;
1345 }
1346 
firstLineBoxBaseline() const1347 int RenderTable::firstLineBoxBaseline() const
1348 {
1349     // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1350     // doesn't define the baseline of a 'table' only an 'inline-table').
1351     // This is also needed to properly determine the baseline of a cell if it has a table child.
1352 
1353     if (isWritingModeRoot())
1354         return -1;
1355 
1356     recalcSectionsIfNeeded();
1357 
1358     const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1359     if (!topNonEmptySection)
1360         return -1;
1361 
1362     int baseline = topNonEmptySection->firstLineBoxBaseline();
1363     if (baseline > 0)
1364         return topNonEmptySection->logicalTop() + baseline;
1365 
1366     // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
1367     return -1;
1368 }
1369 
overflowClipRect(const LayoutPoint & location,RenderRegion * region,OverlayScrollbarSizeRelevancy relevancy)1370 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1371 {
1372     LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
1373 
1374     // If we have a caption, expand the clip to include the caption.
1375     // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1376     // for real until captions have been re-written.
1377     // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1378     // supported.  When we actually support left/right and stop mapping them to top/bottom,
1379     // we might have to hack this code first (depending on what order we do these bug fixes in).
1380     if (!m_captions.isEmpty()) {
1381         if (style()->isHorizontalWritingMode()) {
1382             rect.setHeight(height());
1383             rect.setY(location.y());
1384         } else {
1385             rect.setWidth(width());
1386             rect.setX(location.x());
1387         }
1388     }
1389 
1390     return rect;
1391 }
1392 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction action)1393 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1394 {
1395     LayoutPoint adjustedLocation = accumulatedOffset + location();
1396 
1397     // Check kids first.
1398     if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) {
1399         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1400             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1401                 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1402                 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1403                     updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1404                     return true;
1405                 }
1406             }
1407         }
1408     }
1409 
1410     // Check our bounds next.
1411     LayoutRect boundsRect(adjustedLocation, size());
1412     if (visibleToHitTestRequest(request) && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) {
1413         updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation)));
1414         if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1415             return true;
1416     }
1417 
1418     return false;
1419 }
1420 
createAnonymousWithParentRenderer(const RenderObject * parent)1421 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1422 {
1423     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1424     RenderTable* newTable = new RenderTable(0);
1425     newTable->setDocumentForAnonymous(&parent->document());
1426     newTable->setStyle(newStyle.release());
1427     return newTable;
1428 }
1429 
tableStartBorderAdjoiningCell(const RenderTableCell * cell) const1430 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1431 {
1432     ASSERT(cell->isFirstOrLastCellInRow());
1433     if (hasSameDirectionAs(cell->row()))
1434         return style()->borderStart();
1435 
1436     return style()->borderEnd();
1437 }
1438 
tableEndBorderAdjoiningCell(const RenderTableCell * cell) const1439 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1440 {
1441     ASSERT(cell->isFirstOrLastCellInRow());
1442     if (hasSameDirectionAs(cell->row()))
1443         return style()->borderEnd();
1444 
1445     return style()->borderStart();
1446 }
1447 
1448 }
1449