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