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