1 /*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 * (C) 1997 Torben Weis (weis@kde.org)
4 * (C) 1998 Waldo Bastian (bastian@kde.org)
5 * (C) 1999 Lars Knoll (knoll@kde.org)
6 * (C) 1999 Antti Koivisto (koivisto@kde.org)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
8 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "config.h"
27 #include "RenderTable.h"
28
29 #include "AutoTableLayout.h"
30 #include "DeleteButtonController.h"
31 #include "Document.h"
32 #include "FixedTableLayout.h"
33 #include "FrameView.h"
34 #include "HTMLNames.h"
35 #include "RenderLayer.h"
36 #include "RenderTableCell.h"
37 #include "RenderTableCol.h"
38 #include "RenderTableSection.h"
39 #ifdef ANDROID_LAYOUT
40 #include "Settings.h"
41 #endif
42 #include "RenderView.h"
43
44 using namespace std;
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
RenderTable(Node * node)50 RenderTable::RenderTable(Node* node)
51 : RenderBlock(node)
52 , m_caption(0)
53 , m_head(0)
54 , m_foot(0)
55 , m_firstBody(0)
56 , m_currentBorder(0)
57 , m_hasColElements(false)
58 , m_needsSectionRecalc(0)
59 , m_hSpacing(0)
60 , m_vSpacing(0)
61 , m_borderLeft(0)
62 , m_borderRight(0)
63 {
64 #ifdef ANDROID_LAYOUT
65 m_singleColumn = false;
66 #endif
67 m_columnPos.fill(0, 2);
68 m_columns.fill(ColumnStruct(), 1);
69 }
70
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)71 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
72 {
73 RenderBlock::styleDidChange(diff, oldStyle);
74
75 ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
76
77 // In the collapsed border model, there is no cell spacing.
78 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
79 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
80 m_columnPos[0] = m_hSpacing;
81
82 if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
83 // According to the CSS2 spec, you only use fixed table layout if an
84 // explicit width is specified on the table. Auto width implies auto table layout.
85 if (style()->tableLayout() == TFIXED && !style()->width().isAuto())
86 m_tableLayout.set(new FixedTableLayout(this));
87 else
88 m_tableLayout.set(new AutoTableLayout(this));
89 }
90 }
91
resetSectionPointerIfNotBefore(RenderTableSection * & ptr,RenderObject * before)92 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
93 {
94 if (!before || !ptr)
95 return;
96 RenderObject* o = before->previousSibling();
97 while (o && o != ptr)
98 o = o->previousSibling();
99 if (!o)
100 ptr = 0;
101 }
102
addChild(RenderObject * child,RenderObject * beforeChild)103 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
104 {
105 // Make sure we don't append things after :after-generated content if we have it.
106 if (!beforeChild && isAfterContent(lastChild()))
107 beforeChild = lastChild();
108
109 bool wrapInAnonymousSection = !child->isPositioned();
110
111 if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
112 // First caption wins.
113 if (beforeChild && m_caption) {
114 RenderObject* o = beforeChild->previousSibling();
115 while (o && o != m_caption)
116 o = o->previousSibling();
117 if (!o)
118 m_caption = 0;
119 }
120 if (!m_caption)
121 m_caption = toRenderBlock(child);
122 wrapInAnonymousSection = false;
123 } else if (child->isTableCol()) {
124 m_hasColElements = true;
125 wrapInAnonymousSection = false;
126 } else if (child->isTableSection()) {
127 switch (child->style()->display()) {
128 case TABLE_HEADER_GROUP:
129 resetSectionPointerIfNotBefore(m_head, beforeChild);
130 if (!m_head) {
131 m_head = toRenderTableSection(child);
132 } else {
133 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
134 if (!m_firstBody)
135 m_firstBody = toRenderTableSection(child);
136 }
137 wrapInAnonymousSection = false;
138 break;
139 case TABLE_FOOTER_GROUP:
140 resetSectionPointerIfNotBefore(m_foot, beforeChild);
141 if (!m_foot) {
142 m_foot = toRenderTableSection(child);
143 wrapInAnonymousSection = false;
144 break;
145 }
146 // Fall through.
147 case TABLE_ROW_GROUP:
148 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
149 if (!m_firstBody)
150 m_firstBody = toRenderTableSection(child);
151 wrapInAnonymousSection = false;
152 break;
153 default:
154 ASSERT_NOT_REACHED();
155 }
156 } else if (child->isTableCell() || child->isTableRow())
157 wrapInAnonymousSection = true;
158 else
159 wrapInAnonymousSection = true;
160
161 if (!wrapInAnonymousSection) {
162 // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
163 while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION)
164 beforeChild = beforeChild->parent();
165
166 RenderBox::addChild(child, beforeChild);
167 return;
168 }
169
170 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
171 lastChild()->addChild(child);
172 return;
173 }
174
175 RenderObject* lastBox = beforeChild;
176 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
177 lastBox = lastBox->parent();
178 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
179 lastBox->addChild(child, beforeChild);
180 return;
181 }
182
183 if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
184 beforeChild = 0;
185 RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
186 RefPtr<RenderStyle> newStyle = RenderStyle::create();
187 newStyle->inheritFrom(style());
188 newStyle->setDisplay(TABLE_ROW_GROUP);
189 section->setStyle(newStyle.release());
190 addChild(section, beforeChild);
191 section->addChild(child);
192 }
193
removeChild(RenderObject * oldChild)194 void RenderTable::removeChild(RenderObject* oldChild)
195 {
196 RenderBox::removeChild(oldChild);
197 setNeedsSectionRecalc();
198 }
199
calcWidth()200 void RenderTable::calcWidth()
201 {
202 #ifdef ANDROID_LAYOUT
203 if (view()->frameView()) {
204 const Settings* settings = document()->settings();
205 ASSERT(settings);
206 if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
207 m_visibleWidth = view()->frameView()->screenWidth();
208 }
209 }
210 #endif
211
212 if (isPositioned())
213 calcAbsoluteHorizontal();
214
215 RenderBlock* cb = containingBlock();
216 int availableWidth = cb->availableWidth();
217
218 LengthType widthType = style()->width().type();
219 if (widthType > Relative && style()->width().isPositive()) {
220 // Percent or fixed table
221 setWidth(style()->width().calcMinValue(availableWidth));
222 setWidth(max(minPrefWidth(), width()));
223 } else {
224 // An auto width table should shrink to fit within the line width if necessary in order to
225 // avoid overlapping floats.
226 availableWidth = cb->lineWidth(y(), false);
227
228 // Subtract out any fixed margins from our available width for auto width tables.
229 int marginTotal = 0;
230 if (!style()->marginLeft().isAuto())
231 marginTotal += style()->marginLeft().calcValue(availableWidth);
232 if (!style()->marginRight().isAuto())
233 marginTotal += style()->marginRight().calcValue(availableWidth);
234
235 // Subtract out our margins to get the available content width.
236 int availContentWidth = max(0, availableWidth - marginTotal);
237
238 // Ensure we aren't bigger than our max width or smaller than our min width.
239 setWidth(min(availContentWidth, maxPrefWidth()));
240 }
241
242 setWidth(max(width(), minPrefWidth()));
243
244 // Finally, with our true width determined, compute our margins for real.
245 m_marginRight = 0;
246 m_marginLeft = 0;
247 #ifdef ANDROID_LAYOUT
248 // in SSR mode, we ignore left/right margin for table
249 if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
250 return;
251 #endif
252 calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
253 }
254
layout()255 void RenderTable::layout()
256 {
257 ASSERT(needsLayout());
258
259 if (layoutOnlyPositionedObjects())
260 return;
261
262 recalcSectionsIfNeeded();
263
264 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
265 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
266
267 setHeight(0);
268 m_overflow.clear();
269
270 initMaxMarginValues();
271
272 #ifdef ANDROID_LAYOUT
273 bool relayoutChildren = false;
274 int oldVisibleWidth = m_visibleWidth;
275 #endif
276
277 int oldWidth = width();
278 calcWidth();
279
280 #ifdef ANDROID_LAYOUT
281 if (oldVisibleWidth != m_visibleWidth
282 && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
283 relayoutChildren = true;
284 else if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
285 // if the width of a table is wider than its container width, or it has a nested table,
286 // we will render it with single column.
287 int cw = containingBlockWidthForContent();
288 bool shouldRenderAsSingleColumn = (width() > cw);
289 if (!shouldRenderAsSingleColumn) {
290 RenderObject* child = firstChild();
291 while (child) {
292 if (child->isTable()) {
293 shouldRenderAsSingleColumn = true;
294 break;
295 }
296 child = child->nextInPreOrder();
297 }
298 }
299
300 if (shouldRenderAsSingleColumn) {
301 m_singleColumn = true;
302 if (width() > cw)
303 setWidth(cw);
304 if (m_minPrefWidth > cw)
305 m_minPrefWidth = cw;
306 if (m_maxPrefWidth > cw)
307 m_maxPrefWidth = cw;
308 }
309 }
310 #endif
311 if (m_caption && width() != oldWidth)
312 m_caption->setNeedsLayout(true, false);
313
314 // FIXME: The optimisation below doesn't work since the internal table
315 // layout could have changed. we need to add a flag to the table
316 // layout that tells us if something has changed in the min max
317 // calculations to do it correctly.
318 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
319 m_tableLayout->layout();
320
321 setCellWidths();
322
323 // layout child objects
324 int calculatedHeight = 0;
325 int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;
326
327 bool collapsing = collapseBorders();
328
329 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
330 #ifdef ANDROID_LAYOUT
331 if (relayoutChildren) {
332 child->setNeedsLayout(true, false);
333 if (!child->isTableSection()) {
334 child->layoutIfNeeded();
335 continue;
336 }
337 // fall through
338 }
339 #endif
340 if (child->isTableSection()) {
341 child->layoutIfNeeded();
342 RenderTableSection* section = toRenderTableSection(child);
343 calculatedHeight += section->calcRowHeight();
344 if (collapsing)
345 section->recalcOuterBorder();
346 ASSERT(!section->needsLayout());
347 } else if (child->isTableCol()) {
348 child->layoutIfNeeded();
349 ASSERT(!child->needsLayout());
350 }
351 }
352
353 // Only lay out one caption, since it's the only one we're going to end up painting.
354 if (m_caption)
355 m_caption->layoutIfNeeded();
356
357 // If any table section moved vertically, we will just repaint everything from that
358 // section down (it is quite unlikely that any of the following sections
359 // did not shift).
360 bool sectionMoved = false;
361 int movedSectionTop = 0;
362
363 // FIXME: Collapse caption margin.
364 if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
365 IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
366
367 m_caption->setLocation(m_caption->marginLeft(), height());
368 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
369 m_caption->repaintDuringLayoutIfMoved(captionRect);
370
371 setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
372
373 if (height() != oldTableTop) {
374 sectionMoved = true;
375 movedSectionTop = min(height(), oldTableTop);
376 }
377 }
378
379 int bpTop = borderTop() + (collapsing ? 0 : paddingTop());
380 int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom());
381
382 setHeight(height() + bpTop);
383
384 if (!isPositioned())
385 calcHeight();
386
387 Length h = style()->height();
388 int th = 0;
389 if (h.isFixed())
390 // Tables size as though CSS height includes border/padding.
391 th = h.value() - (bpTop + bpBottom);
392 else if (h.isPercent())
393 th = calcPercentageHeight(h);
394 th = max(0, th);
395
396 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
397 if (child->isTableSection())
398 // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
399 toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0);
400 }
401
402 if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) {
403 // Completely empty tables (with no sections or anything) should at least honor specified height
404 // in strict mode.
405 setHeight(height() + th);
406 }
407
408 int bl = borderLeft();
409 if (!collapsing)
410 bl += paddingLeft();
411
412 // position the table sections
413 RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
414 while (section) {
415 if (!sectionMoved && section->y() != height()) {
416 sectionMoved = true;
417 movedSectionTop = min(height(), section->y()) + section->topVisibleOverflow();
418 }
419 section->setLocation(bl, height());
420
421 setHeight(height() + section->height());
422 section = sectionBelow(section);
423 }
424
425 setHeight(height() + bpBottom);
426
427 if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
428 IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
429
430 m_caption->setLocation(m_caption->marginLeft(), height());
431 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
432 m_caption->repaintDuringLayoutIfMoved(captionRect);
433
434 setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
435 }
436
437 if (isPositioned())
438 calcHeight();
439
440 // table can be containing block of positioned elements.
441 // FIXME: Only pass true if width or height changed.
442 layoutPositionedObjects(true);
443
444 // Add overflow from borders.
445 int rightBorderOverflow = width() + (collapsing ? outerBorderRight() - borderRight() : 0);
446 int leftBorderOverflow = collapsing ? borderLeft() - outerBorderLeft() : 0;
447 int bottomBorderOverflow = height() + (collapsing ? outerBorderBottom() - borderBottom() : 0);
448 int topBorderOverflow = collapsing ? borderTop() - outerBorderTop() : 0;
449 addLayoutOverflow(IntRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow));
450
451 // Add visual overflow from box-shadow and reflections.
452 addShadowOverflow();
453
454 // Add overflow from our caption.
455 if (m_caption)
456 addOverflowFromChild(m_caption);
457
458 // Add overflow from our sections.
459 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
460 if (child->isTableSection()) {
461 RenderTableSection* section = toRenderTableSection(child);
462 addOverflowFromChild(section);
463 }
464 }
465
466 statePusher.pop();
467
468 bool didFullRepaint = repainter.repaintAfterLayout();
469 // Repaint with our new bounds if they are different from our old bounds.
470 if (!didFullRepaint && sectionMoved)
471 repaintRectangle(IntRect(leftVisibleOverflow(), movedSectionTop, rightVisibleOverflow() - leftVisibleOverflow(), bottomVisibleOverflow() - movedSectionTop));
472
473 setNeedsLayout(false);
474 }
475
setCellWidths()476 void RenderTable::setCellWidths()
477 {
478 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
479 if (child->isTableSection())
480 toRenderTableSection(child)->setCellWidths();
481 }
482 }
483
paint(PaintInfo & paintInfo,int tx,int ty)484 void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
485 {
486 tx += x();
487 ty += y();
488
489 PaintPhase paintPhase = paintInfo.phase;
490
491 int os = 2 * maximalOutlineSize(paintPhase);
492 if (ty + topVisibleOverflow() >= paintInfo.rect.bottom() + os || ty + bottomVisibleOverflow() <= paintInfo.rect.y() - os)
493 return;
494 if (tx + leftVisibleOverflow() >= paintInfo.rect.right() + os || tx + rightVisibleOverflow() <= paintInfo.rect.x() - os)
495 return;
496
497 bool pushedClip = pushContentsClip(paintInfo, tx, ty);
498 paintObject(paintInfo, tx, ty);
499 if (pushedClip)
500 popContentsClip(paintInfo, paintPhase, tx, ty);
501 }
502
paintObject(PaintInfo & paintInfo,int tx,int ty)503 void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty)
504 {
505 PaintPhase paintPhase = paintInfo.phase;
506 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
507 paintBoxDecorations(paintInfo, tx, ty);
508
509 if (paintPhase == PaintPhaseMask) {
510 paintMask(paintInfo, tx, ty);
511 return;
512 }
513
514 // We're done. We don't bother painting any children.
515 if (paintPhase == PaintPhaseBlockBackground)
516 return;
517
518 // We don't paint our own background, but we do let the kids paint their backgrounds.
519 if (paintPhase == PaintPhaseChildBlockBackgrounds)
520 paintPhase = PaintPhaseChildBlockBackground;
521
522 PaintInfo info(paintInfo);
523 info.phase = paintPhase;
524 info.paintingRoot = paintingRootForChildren(paintInfo);
525
526 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
527 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption))
528 child->paint(info, tx, ty);
529 }
530
531 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
532 // Collect all the unique border styles that we want to paint in a sorted list. Once we
533 // have all the styles sorted, we then do individual passes, painting each style of border
534 // from lowest precedence to highest precedence.
535 info.phase = PaintPhaseCollapsedTableBorders;
536 RenderTableCell::CollapsedBorderStyles borderStyles;
537 RenderObject* stop = nextInPreOrderAfterChildren();
538 for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
539 if (o->isTableCell())
540 toRenderTableCell(o)->collectBorderStyles(borderStyles);
541 RenderTableCell::sortBorderStyles(borderStyles);
542 size_t count = borderStyles.size();
543 for (size_t i = 0; i < count; ++i) {
544 m_currentBorder = &borderStyles[i];
545 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
546 if (child->isTableSection())
547 child->paint(info, tx, ty);
548 }
549 m_currentBorder = 0;
550 }
551 }
552
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)553 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
554 {
555 if (!shouldPaintWithinRoot(paintInfo))
556 return;
557
558 int w = width();
559 int h = height();
560
561 // Account for the caption.
562 if (m_caption) {
563 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
564 h -= captionHeight;
565 if (m_caption->style()->captionSide() != CAPBOTTOM)
566 ty += captionHeight;
567 }
568
569 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
570
571 paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h);
572 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
573
574 if (style()->hasBorder() && !collapseBorders())
575 paintBorder(paintInfo.context, tx, ty, w, h, style());
576 }
577
paintMask(PaintInfo & paintInfo,int tx,int ty)578 void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty)
579 {
580 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
581 return;
582
583 int w = width();
584 int h = height();
585
586 // Account for the caption.
587 if (m_caption) {
588 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
589 h -= captionHeight;
590 if (m_caption->style()->captionSide() != CAPBOTTOM)
591 ty += captionHeight;
592 }
593
594 paintMaskImages(paintInfo, tx, ty, w, h);
595 }
596
calcPrefWidths()597 void RenderTable::calcPrefWidths()
598 {
599 ASSERT(prefWidthsDirty());
600
601 recalcSectionsIfNeeded();
602 recalcHorizontalBorders();
603
604 m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth);
605
606 if (m_caption)
607 m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth());
608
609 setPrefWidthsDirty(false);
610 }
611
splitColumn(int pos,int firstSpan)612 void RenderTable::splitColumn(int pos, int firstSpan)
613 {
614 // we need to add a new columnStruct
615 int oldSize = m_columns.size();
616 m_columns.grow(oldSize + 1);
617 int oldSpan = m_columns[pos].span;
618 ASSERT(oldSpan > firstSpan);
619 m_columns[pos].span = firstSpan;
620 memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
621 m_columns[pos + 1].span = oldSpan - firstSpan;
622
623 // change width of all rows.
624 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
625 if (child->isTableSection())
626 toRenderTableSection(child)->splitColumn(pos, oldSize + 1);
627 }
628
629 m_columnPos.grow(numEffCols() + 1);
630 setNeedsLayoutAndPrefWidthsRecalc();
631 }
632
appendColumn(int span)633 void RenderTable::appendColumn(int span)
634 {
635 // easy case.
636 int pos = m_columns.size();
637 int newSize = pos + 1;
638 m_columns.grow(newSize);
639 m_columns[pos].span = span;
640
641 // change width of all rows.
642 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
643 if (child->isTableSection())
644 toRenderTableSection(child)->appendColumn(pos);
645 }
646
647 m_columnPos.grow(numEffCols() + 1);
648 setNeedsLayoutAndPrefWidthsRecalc();
649 }
650
colElement(int col,bool * startEdge,bool * endEdge) const651 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
652 {
653 if (!m_hasColElements)
654 return 0;
655 RenderObject* child = firstChild();
656 int cCol = 0;
657
658 while (child) {
659 if (child->isTableCol()) {
660 RenderTableCol* colElem = toRenderTableCol(child);
661 int span = colElem->span();
662 if (!colElem->firstChild()) {
663 int startCol = cCol;
664 int endCol = cCol + span - 1;
665 cCol += span;
666 if (cCol > col) {
667 if (startEdge)
668 *startEdge = startCol == col;
669 if (endEdge)
670 *endEdge = endCol == col;
671 return colElem;
672 }
673 }
674
675 RenderObject* next = child->firstChild();
676 if (!next)
677 next = child->nextSibling();
678 if (!next && child->parent()->isTableCol())
679 next = child->parent()->nextSibling();
680 child = next;
681 } else if (child == m_caption)
682 child = child->nextSibling();
683 else
684 break;
685 }
686
687 return 0;
688 }
689
recalcSections() const690 void RenderTable::recalcSections() const
691 {
692 m_caption = 0;
693 m_head = 0;
694 m_foot = 0;
695 m_firstBody = 0;
696 m_hasColElements = false;
697
698 // We need to get valid pointers to caption, head, foot and first body again
699 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
700 switch (child->style()->display()) {
701 case TABLE_CAPTION:
702 if (!m_caption && child->isRenderBlock()) {
703 m_caption = toRenderBlock(child);
704 m_caption->setNeedsLayout(true);
705 }
706 break;
707 case TABLE_COLUMN:
708 case TABLE_COLUMN_GROUP:
709 m_hasColElements = true;
710 break;
711 case TABLE_HEADER_GROUP:
712 if (child->isTableSection()) {
713 RenderTableSection* section = toRenderTableSection(child);
714 if (!m_head)
715 m_head = section;
716 else if (!m_firstBody)
717 m_firstBody = section;
718 section->recalcCellsIfNeeded();
719 }
720 break;
721 case TABLE_FOOTER_GROUP:
722 if (child->isTableSection()) {
723 RenderTableSection* section = toRenderTableSection(child);
724 if (!m_foot)
725 m_foot = section;
726 else if (!m_firstBody)
727 m_firstBody = section;
728 section->recalcCellsIfNeeded();
729 }
730 break;
731 case TABLE_ROW_GROUP:
732 if (child->isTableSection()) {
733 RenderTableSection* section = toRenderTableSection(child);
734 if (!m_firstBody)
735 m_firstBody = section;
736 section->recalcCellsIfNeeded();
737 }
738 break;
739 default:
740 break;
741 }
742 }
743
744 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
745 int maxCols = 0;
746 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
747 if (child->isTableSection()) {
748 RenderTableSection* section = toRenderTableSection(child);
749 int sectionCols = section->numColumns();
750 if (sectionCols > maxCols)
751 maxCols = sectionCols;
752 }
753 }
754
755 m_columns.resize(maxCols);
756 m_columnPos.resize(maxCols + 1);
757
758 ASSERT(selfNeedsLayout());
759
760 m_needsSectionRecalc = false;
761 }
762
calcBorderLeft() const763 int RenderTable::calcBorderLeft() const
764 {
765 if (collapseBorders()) {
766 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
767 if (!numEffCols())
768 return 0;
769
770 unsigned borderWidth = 0;
771
772 const BorderValue& tb = style()->borderLeft();
773 if (tb.style() == BHIDDEN)
774 return 0;
775 if (tb.style() > BHIDDEN)
776 borderWidth = tb.width;
777
778 int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
779 RenderTableCol* colGroup = colElement(leftmostColumn);
780 if (colGroup) {
781 const BorderValue& gb = style()->borderLeft();
782 if (gb.style() == BHIDDEN)
783 return 0;
784 if (gb.style() > BHIDDEN)
785 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
786 }
787
788 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
789 if (firstNonEmptySection && !firstNonEmptySection->numRows())
790 firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
791
792 if (firstNonEmptySection) {
793 const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
794 if (sb.style() == BHIDDEN)
795 return 0;
796
797 if (sb.style() > BHIDDEN)
798 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
799
800 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
801
802 if (cs.cell) {
803 const BorderValue& cb = cs.cell->style()->borderLeft();
804 if (cb.style() == BHIDDEN)
805 return 0;
806
807 const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
808 if (rb.style() == BHIDDEN)
809 return 0;
810
811 if (cb.style() > BHIDDEN)
812 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
813 if (rb.style() > BHIDDEN)
814 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
815 }
816 }
817 return borderWidth / 2;
818 }
819 return RenderBlock::borderLeft();
820 }
821
calcBorderRight() const822 int RenderTable::calcBorderRight() const
823 {
824 if (collapseBorders()) {
825 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
826 if (!numEffCols())
827 return 0;
828
829 unsigned borderWidth = 0;
830
831 const BorderValue& tb = style()->borderRight();
832 if (tb.style() == BHIDDEN)
833 return 0;
834 if (tb.style() > BHIDDEN)
835 borderWidth = tb.width;
836
837 int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
838 RenderTableCol* colGroup = colElement(rightmostColumn);
839 if (colGroup) {
840 const BorderValue& gb = style()->borderRight();
841 if (gb.style() == BHIDDEN)
842 return 0;
843 if (gb.style() > BHIDDEN)
844 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
845 }
846
847 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
848 if (firstNonEmptySection && !firstNonEmptySection->numRows())
849 firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
850
851 if (firstNonEmptySection) {
852 const BorderValue& sb = firstNonEmptySection->style()->borderRight();
853 if (sb.style() == BHIDDEN)
854 return 0;
855
856 if (sb.style() > BHIDDEN)
857 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
858
859 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
860
861 if (cs.cell) {
862 const BorderValue& cb = cs.cell->style()->borderRight();
863 if (cb.style() == BHIDDEN)
864 return 0;
865
866 const BorderValue& rb = cs.cell->parent()->style()->borderRight();
867 if (rb.style() == BHIDDEN)
868 return 0;
869
870 if (cb.style() > BHIDDEN)
871 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
872 if (rb.style() > BHIDDEN)
873 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
874 }
875 }
876 return (borderWidth + 1) / 2;
877 }
878 return RenderBlock::borderRight();
879 }
880
recalcHorizontalBorders()881 void RenderTable::recalcHorizontalBorders()
882 {
883 m_borderLeft = calcBorderLeft();
884 m_borderRight = calcBorderRight();
885 }
886
borderTop() const887 int RenderTable::borderTop() const
888 {
889 if (collapseBorders())
890 return outerBorderTop();
891 return RenderBlock::borderTop();
892 }
893
borderBottom() const894 int RenderTable::borderBottom() const
895 {
896 if (collapseBorders())
897 return outerBorderBottom();
898 return RenderBlock::borderBottom();
899 }
900
outerBorderTop() const901 int RenderTable::outerBorderTop() const
902 {
903 if (!collapseBorders())
904 return 0;
905 int borderWidth = 0;
906 RenderTableSection* topSection;
907 if (m_head)
908 topSection = m_head;
909 else if (m_firstBody)
910 topSection = m_firstBody;
911 else if (m_foot)
912 topSection = m_foot;
913 else
914 topSection = 0;
915 if (topSection) {
916 borderWidth = topSection->outerBorderTop();
917 if (borderWidth == -1)
918 return 0; // Overridden by hidden
919 }
920 const BorderValue& tb = style()->borderTop();
921 if (tb.style() == BHIDDEN)
922 return 0;
923 if (tb.style() > BHIDDEN)
924 borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
925 return borderWidth;
926 }
927
outerBorderBottom() const928 int RenderTable::outerBorderBottom() const
929 {
930 if (!collapseBorders())
931 return 0;
932 int borderWidth = 0;
933 RenderTableSection* bottomSection;
934 if (m_foot)
935 bottomSection = m_foot;
936 else {
937 RenderObject* child;
938 for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { }
939 bottomSection = child ? toRenderTableSection(child) : 0;
940 }
941 if (bottomSection) {
942 borderWidth = bottomSection->outerBorderBottom();
943 if (borderWidth == -1)
944 return 0; // Overridden by hidden
945 }
946 const BorderValue& tb = style()->borderBottom();
947 if (tb.style() == BHIDDEN)
948 return 0;
949 if (tb.style() > BHIDDEN)
950 borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
951 return borderWidth;
952 }
953
outerBorderLeft() const954 int RenderTable::outerBorderLeft() const
955 {
956 if (!collapseBorders())
957 return 0;
958
959 int borderWidth = 0;
960
961 const BorderValue& tb = style()->borderLeft();
962 if (tb.style() == BHIDDEN)
963 return 0;
964 if (tb.style() > BHIDDEN)
965 borderWidth = tb.width / 2;
966
967 bool allHidden = true;
968 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
969 if (!child->isTableSection())
970 continue;
971 int sw = toRenderTableSection(child)->outerBorderLeft();
972 if (sw == -1)
973 continue;
974 else
975 allHidden = false;
976 borderWidth = max(borderWidth, sw);
977 }
978 if (allHidden)
979 return 0;
980
981 return borderWidth;
982 }
983
outerBorderRight() const984 int RenderTable::outerBorderRight() const
985 {
986 if (!collapseBorders())
987 return 0;
988
989 int borderWidth = 0;
990
991 const BorderValue& tb = style()->borderRight();
992 if (tb.style() == BHIDDEN)
993 return 0;
994 if (tb.style() > BHIDDEN)
995 borderWidth = (tb.width + 1) / 2;
996
997 bool allHidden = true;
998 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
999 if (!child->isTableSection())
1000 continue;
1001 int sw = toRenderTableSection(child)->outerBorderRight();
1002 if (sw == -1)
1003 continue;
1004 else
1005 allHidden = false;
1006 borderWidth = max(borderWidth, sw);
1007 }
1008 if (allHidden)
1009 return 0;
1010
1011 return borderWidth;
1012 }
1013
sectionAbove(const RenderTableSection * section,bool skipEmptySections) const1014 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
1015 {
1016 recalcSectionsIfNeeded();
1017
1018 if (section == m_head)
1019 return 0;
1020
1021 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1022 while (prevSection) {
1023 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || toRenderTableSection(prevSection)->numRows()))
1024 break;
1025 prevSection = prevSection->previousSibling();
1026 }
1027 if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
1028 prevSection = m_head;
1029 return toRenderTableSection(prevSection);
1030 }
1031
sectionBelow(const RenderTableSection * section,bool skipEmptySections) const1032 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
1033 {
1034 recalcSectionsIfNeeded();
1035
1036 if (section == m_foot)
1037 return 0;
1038
1039 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1040 while (nextSection) {
1041 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || toRenderTableSection(nextSection)->numRows()))
1042 break;
1043 nextSection = nextSection->nextSibling();
1044 }
1045 if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
1046 nextSection = m_foot;
1047 return toRenderTableSection(nextSection);
1048 }
1049
cellAbove(const RenderTableCell * cell) const1050 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1051 {
1052 recalcSectionsIfNeeded();
1053
1054 // Find the section and row to look in
1055 int r = cell->row();
1056 RenderTableSection* section = 0;
1057 int rAbove = 0;
1058 if (r > 0) {
1059 // cell is not in the first row, so use the above row in its own section
1060 section = cell->section();
1061 rAbove = r - 1;
1062 } else {
1063 section = sectionAbove(cell->section(), true);
1064 if (section)
1065 rAbove = section->numRows() - 1;
1066 }
1067
1068 // Look up the cell in the section's grid, which requires effective col index
1069 if (section) {
1070 int effCol = colToEffCol(cell->col());
1071 RenderTableSection::CellStruct aboveCell;
1072 // If we hit a span back up to a real cell.
1073 do {
1074 aboveCell = section->cellAt(rAbove, effCol);
1075 effCol--;
1076 } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
1077 return aboveCell.cell;
1078 } else
1079 return 0;
1080 }
1081
cellBelow(const RenderTableCell * cell) const1082 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1083 {
1084 recalcSectionsIfNeeded();
1085
1086 // Find the section and row to look in
1087 int r = cell->row() + cell->rowSpan() - 1;
1088 RenderTableSection* section = 0;
1089 int rBelow = 0;
1090 if (r < cell->section()->numRows() - 1) {
1091 // The cell is not in the last row, so use the next row in the section.
1092 section = cell->section();
1093 rBelow = r + 1;
1094 } else {
1095 section = sectionBelow(cell->section(), true);
1096 if (section)
1097 rBelow = 0;
1098 }
1099
1100 // Look up the cell in the section's grid, which requires effective col index
1101 if (section) {
1102 int effCol = colToEffCol(cell->col());
1103 RenderTableSection::CellStruct belowCell;
1104 // If we hit a colspan back up to a real cell.
1105 do {
1106 belowCell = section->cellAt(rBelow, effCol);
1107 effCol--;
1108 } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
1109 return belowCell.cell;
1110 } else
1111 return 0;
1112 }
1113
cellBefore(const RenderTableCell * cell) const1114 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1115 {
1116 recalcSectionsIfNeeded();
1117
1118 RenderTableSection* section = cell->section();
1119 int effCol = colToEffCol(cell->col());
1120 if (!effCol)
1121 return 0;
1122
1123 // If we hit a colspan back up to a real cell.
1124 RenderTableSection::CellStruct prevCell;
1125 do {
1126 prevCell = section->cellAt(cell->row(), effCol - 1);
1127 effCol--;
1128 } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
1129 return prevCell.cell;
1130 }
1131
cellAfter(const RenderTableCell * cell) const1132 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1133 {
1134 recalcSectionsIfNeeded();
1135
1136 int effCol = colToEffCol(cell->col() + cell->colSpan());
1137 if (effCol >= numEffCols())
1138 return 0;
1139 return cell->section()->cellAt(cell->row(), effCol).cell;
1140 }
1141
firstLineBlock() const1142 RenderBlock* RenderTable::firstLineBlock() const
1143 {
1144 return 0;
1145 }
1146
updateFirstLetter()1147 void RenderTable::updateFirstLetter()
1148 {
1149 }
1150
firstLineBoxBaseline() const1151 int RenderTable::firstLineBoxBaseline() const
1152 {
1153 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
1154 if (firstNonEmptySection && !firstNonEmptySection->numRows())
1155 firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
1156
1157 if (!firstNonEmptySection)
1158 return -1;
1159
1160 return firstNonEmptySection->y() + firstNonEmptySection->firstLineBoxBaseline();
1161 }
1162
overflowClipRect(int tx,int ty)1163 IntRect RenderTable::overflowClipRect(int tx, int ty)
1164 {
1165 IntRect rect = RenderBlock::overflowClipRect(tx, ty);
1166
1167 // If we have a caption, expand the clip to include the caption.
1168 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1169 // for real until captions have been re-written.
1170 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1171 // supported. When we actually support left/right and stop mapping them to top/bottom,
1172 // we might have to hack this code first (depending on what order we do these bug fixes in).
1173 if (m_caption) {
1174 rect.setHeight(height());
1175 rect.setY(ty);
1176 }
1177
1178 return rect;
1179 }
1180
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction action)1181 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
1182 {
1183 tx += x();
1184 ty += y();
1185
1186 // Check kids first.
1187 if (!hasOverflowClip() || overflowClipRect(tx, ty).contains(xPos, yPos)) {
1188 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1189 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) &&
1190 child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
1191 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1192 return true;
1193 }
1194 }
1195 }
1196
1197 // Check our bounds next.
1198 if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
1199 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1200 return true;
1201 }
1202
1203 return false;
1204 }
1205
1206 }
1207