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, 2009 Apple Inc. All rights reserved.
8 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
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 "RenderTableCol.h"
28
29#include "HTMLNames.h"
30#include "HTMLTableColElement.h"
31#include "RenderChildIterator.h"
32#include "RenderIterator.h"
33#include "RenderTable.h"
34#include "RenderTableCaption.h"
35#include "RenderTableCell.h"
36#include <wtf/IsoMallocInlines.h>
37
38namespace WebCore {
39
40using namespace HTMLNames;
41
42WTF_MAKE_ISO_ALLOCATED_IMPL(RenderTableCol);
43
44RenderTableCol::RenderTableCol(Element& element, RenderStyle&& style)
45 : RenderBox(element, WTFMove(style), 0)
46{
47 // init RenderObject attributes
48 setInline(true); // our object is not Inline
49 updateFromElement();
50}
51
52void RenderTableCol::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
53{
54 RenderBox::styleDidChange(diff, oldStyle);
55 RenderTable* table = this->table();
56 if (!table)
57 return;
58 // If border was changed, notify table.
59 if (oldStyle && oldStyle->border() != style().border())
60 table->invalidateCollapsedBorders();
61 else if (oldStyle->width() != style().width()) {
62 table->recalcSectionsIfNeeded();
63 for (auto& section : childrenOfType<RenderTableSection>(*table)) {
64 unsigned nEffCols = table->numEffCols();
65 for (unsigned j = 0; j < nEffCols; j++) {
66 unsigned rowCount = section.numRows();
67 for (unsigned i = 0; i < rowCount; i++) {
68 RenderTableCell* cell = section.primaryCellAt(i, j);
69 if (!cell)
70 continue;
71 cell->setPreferredLogicalWidthsDirty(true);
72 }
73 }
74 }
75 }
76}
77
78void RenderTableCol::updateFromElement()
79{
80 unsigned oldSpan = m_span;
81 if (element().hasTagName(colTag) || element().hasTagName(colgroupTag)) {
82 HTMLTableColElement& tc = static_cast<HTMLTableColElement&>(element());
83 m_span = tc.span();
84 } else
85 m_span = !(hasInitializedStyle() && style().display() == DisplayType::TableColumnGroup);
86 if (m_span != oldSpan && hasInitializedStyle() && parent())
87 setNeedsLayoutAndPrefWidthsRecalc();
88}
89
90void RenderTableCol::insertedIntoTree()
91{
92 RenderBox::insertedIntoTree();
93 table()->addColumn(this);
94}
95
96void RenderTableCol::willBeRemovedFromTree()
97{
98 RenderBox::willBeRemovedFromTree();
99 table()->removeColumn(this);
100}
101
102bool RenderTableCol::isChildAllowed(const RenderObject& child, const RenderStyle& style) const
103{
104 // We cannot use isTableColumn here as style() may return 0.
105 return style.display() == DisplayType::TableColumn && child.isRenderTableCol();
106}
107
108bool RenderTableCol::canHaveChildren() const
109{
110 // Cols cannot have children. This is actually necessary to fix a bug
111 // with libraries.uc.edu, which makes a <p> be a table-column.
112 return isTableColumnGroup();
113}
114
115LayoutRect RenderTableCol::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
116{
117 // For now, just repaint the whole table.
118 // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
119 // might have propagated a background color or borders into.
120 // FIXME: check for repaintContainer each time here?
121
122 RenderTable* parentTable = table();
123 if (!parentTable)
124 return LayoutRect();
125 return parentTable->clippedOverflowRectForRepaint(repaintContainer);
126}
127
128void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*)
129{
130 // FIXME: Repaint only the rect the image paints in.
131 repaint();
132}
133
134void RenderTableCol::clearPreferredLogicalWidthsDirtyBits()
135{
136 setPreferredLogicalWidthsDirty(false);
137
138 for (auto& child : childrenOfType<RenderObject>(*this))
139 child.setPreferredLogicalWidthsDirty(false);
140}
141
142RenderTable* RenderTableCol::table() const
143{
144 auto table = parent();
145 if (table && !is<RenderTable>(*table))
146 table = table->parent();
147 return is<RenderTable>(table) ? downcast<RenderTable>(table) : nullptr;
148}
149
150RenderTableCol* RenderTableCol::enclosingColumnGroup() const
151{
152 if (!is<RenderTableCol>(*parent()))
153 return nullptr;
154
155 RenderTableCol& parentColumnGroup = downcast<RenderTableCol>(*parent());
156 ASSERT(parentColumnGroup.isTableColumnGroup());
157 ASSERT(isTableColumn());
158 return &parentColumnGroup;
159}
160
161RenderTableCol* RenderTableCol::nextColumn() const
162{
163 // If |this| is a column-group, the next column is the colgroup's first child column.
164 if (RenderObject* firstChild = this->firstChild())
165 return downcast<RenderTableCol>(firstChild);
166
167 // Otherwise it's the next column along.
168 RenderObject* next = nextSibling();
169
170 // Failing that, the child is the last column in a column-group, so the next column is the next column/column-group after its column-group.
171 if (!next && is<RenderTableCol>(*parent()))
172 next = parent()->nextSibling();
173
174 for (; next && !is<RenderTableCol>(*next); next = next->nextSibling()) {
175 // We allow captions mixed with columns and column-groups.
176 if (is<RenderTableCaption>(*next))
177 continue;
178
179 return nullptr;
180 }
181
182 return downcast<RenderTableCol>(next);
183}
184
185const BorderValue& RenderTableCol::borderAdjoiningCellStartBorder() const
186{
187 return style().borderStart();
188}
189
190const BorderValue& RenderTableCol::borderAdjoiningCellEndBorder() const
191{
192 return style().borderEnd();
193}
194
195const BorderValue& RenderTableCol::borderAdjoiningCellBefore(const RenderTableCell& cell) const
196{
197 ASSERT_UNUSED(cell, table()->colElement(cell.col() + cell.colSpan()) == this);
198 return style().borderStart();
199}
200
201const BorderValue& RenderTableCol::borderAdjoiningCellAfter(const RenderTableCell& cell) const
202{
203 ASSERT_UNUSED(cell, table()->colElement(cell.col() - 1) == this);
204 return style().borderEnd();
205}
206
207LayoutUnit RenderTableCol::offsetLeft() const
208{
209 return table()->offsetLeftForColumn(*this);
210}
211
212LayoutUnit RenderTableCol::offsetTop() const
213{
214 return table()->offsetTopForColumn(*this);
215}
216
217LayoutUnit RenderTableCol::offsetWidth() const
218{
219 return table()->offsetWidthForColumn(*this);
220}
221
222LayoutUnit RenderTableCol::offsetHeight() const
223{
224 return table()->offsetHeightForColumn(*this);
225}
226
227}
228