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