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