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 "RenderTable.h"
32#include "RenderTableCell.h"
33
34namespace WebCore {
35
36using namespace HTMLNames;
37
38RenderTableCol::RenderTableCol(Element* element)
39    : RenderBox(element)
40    , m_span(1)
41{
42    // init RenderObject attributes
43    setInline(true); // our object is not Inline
44    updateFromElement();
45}
46
47void RenderTableCol::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
48{
49    RenderBox::styleDidChange(diff, oldStyle);
50
51    // If border was changed, notify table.
52    if (parent()) {
53        RenderTable* table = this->table();
54        if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border())
55            table->invalidateCollapsedBorders();
56    }
57}
58
59void RenderTableCol::updateFromElement()
60{
61    unsigned oldSpan = m_span;
62    Node* n = node();
63    if (n && (n->hasTagName(colTag) || n->hasTagName(colgroupTag))) {
64        HTMLTableColElement* tc = static_cast<HTMLTableColElement*>(n);
65        m_span = tc->span();
66    } else
67        m_span = !(style() && style()->display() == TABLE_COLUMN_GROUP);
68    if (m_span != oldSpan && style() && parent())
69        setNeedsLayoutAndPrefWidthsRecalc();
70}
71
72void RenderTableCol::insertedIntoTree()
73{
74    RenderBox::insertedIntoTree();
75    table()->addColumn(this);
76}
77
78void RenderTableCol::willBeRemovedFromTree()
79{
80    RenderBox::willBeRemovedFromTree();
81    table()->removeColumn(this);
82}
83
84bool RenderTableCol::isChildAllowed(RenderObject* child, RenderStyle* style) const
85{
86    // We cannot use isTableColumn here as style() may return 0.
87    return child->isRenderTableCol() && style->display() == TABLE_COLUMN;
88}
89
90bool RenderTableCol::canHaveChildren() const
91{
92    // Cols cannot have children. This is actually necessary to fix a bug
93    // with libraries.uc.edu, which makes a <p> be a table-column.
94    return isTableColumnGroup();
95}
96
97LayoutRect RenderTableCol::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
98{
99    // For now, just repaint the whole table.
100    // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
101    // might have propagated a background color or borders into.
102    // FIXME: check for repaintContainer each time here?
103
104    RenderTable* parentTable = table();
105    if (!parentTable)
106        return LayoutRect();
107    return parentTable->clippedOverflowRectForRepaint(repaintContainer);
108}
109
110void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*)
111{
112    // FIXME: Repaint only the rect the image paints in.
113    repaint();
114}
115
116void RenderTableCol::clearPreferredLogicalWidthsDirtyBits()
117{
118    setPreferredLogicalWidthsDirty(false);
119
120    for (RenderObject* child = firstChild(); child; child = child->nextSibling())
121        child->setPreferredLogicalWidthsDirty(false);
122}
123
124RenderTable* RenderTableCol::table() const
125{
126    RenderObject* table = parent();
127    if (table && !table->isTable())
128        table = table->parent();
129    return table && table->isTable() ? toRenderTable(table) : 0;
130}
131
132RenderTableCol* RenderTableCol::enclosingColumnGroup() const
133{
134    if (!parent()->isRenderTableCol())
135        return 0;
136
137    RenderTableCol* parentColumnGroup = toRenderTableCol(parent());
138    ASSERT(parentColumnGroup->isTableColumnGroup());
139    ASSERT(isTableColumn());
140    return parentColumnGroup;
141}
142
143RenderTableCol* RenderTableCol::nextColumn() const
144{
145    // If |this| is a column-group, the next column is the colgroup's first child column.
146    if (RenderObject* firstChild = this->firstChild())
147        return toRenderTableCol(firstChild);
148
149    // Otherwise it's the next column along.
150    RenderObject* next = nextSibling();
151
152    // 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.
153    if (!next && parent()->isRenderTableCol())
154        next = parent()->nextSibling();
155
156    for (; next && !next->isRenderTableCol(); next = next->nextSibling()) {
157        // We allow captions mixed with columns and column-groups.
158        if (next->isTableCaption())
159            continue;
160
161        return 0;
162    }
163
164    return toRenderTableCol(next);
165}
166
167const BorderValue& RenderTableCol::borderAdjoiningCellStartBorder(const RenderTableCell*) const
168{
169    return style()->borderStart();
170}
171
172const BorderValue& RenderTableCol::borderAdjoiningCellEndBorder(const RenderTableCell*) const
173{
174    return style()->borderEnd();
175}
176
177const BorderValue& RenderTableCol::borderAdjoiningCellBefore(const RenderTableCell* cell) const
178{
179    ASSERT_UNUSED(cell, table()->colElement(cell->col() + cell->colSpan()) == this);
180    return style()->borderStart();
181}
182
183const BorderValue& RenderTableCol::borderAdjoiningCellAfter(const RenderTableCell* cell) const
184{
185    ASSERT_UNUSED(cell, table()->colElement(cell->col() - 1) == this);
186    return style()->borderEnd();
187}
188
189}
190