1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "RenderTreeBuilderTable.h"
28
29#include "RenderTableCaption.h"
30#include "RenderTableCell.h"
31#include "RenderTableCol.h"
32#include "RenderTableRow.h"
33#include "RenderTreeBuilder.h"
34
35namespace WebCore {
36
37RenderTreeBuilder::Table::Table(RenderTreeBuilder& builder)
38 : m_builder(builder)
39{
40}
41
42RenderElement& RenderTreeBuilder::Table::findOrCreateParentForChild(RenderTableRow& parent, const RenderObject& child, RenderObject*& beforeChild)
43{
44 if (is<RenderTableCell>(child))
45 return parent;
46
47 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == &parent) {
48 auto* previousSibling = beforeChild->previousSibling();
49 if (is<RenderTableCell>(previousSibling) && previousSibling->isAnonymous()) {
50 beforeChild = nullptr;
51 return downcast<RenderElement>(*previousSibling);
52 }
53 }
54
55 auto* lastChild = beforeChild ? beforeChild : parent.lastCell();
56 if (lastChild) {
57 if (is<RenderTableCell>(*lastChild) && lastChild->isAnonymous() && !lastChild->isBeforeOrAfterContent()) {
58 if (beforeChild == lastChild)
59 beforeChild = downcast<RenderElement>(*lastChild).firstChild();
60 return downcast<RenderElement>(*lastChild);
61 }
62
63 // Try to find an anonymous container for the child.
64 if (auto* lastChildParent = lastChild->parent()) {
65 if (lastChildParent->isAnonymous() && !lastChildParent->isBeforeOrAfterContent()) {
66 // If beforeChild is inside an anonymous cell, insert into the cell.
67 if (!is<RenderTableCell>(*lastChild))
68 return *lastChildParent;
69 // If beforeChild is inside an anonymous row, insert into the row.
70 if (is<RenderTableRow>(*lastChildParent)) {
71 auto newCell = RenderTableCell::createAnonymousWithParentRenderer(parent);
72 auto& cell = *newCell;
73 m_builder.attach(*lastChildParent, WTFMove(newCell), beforeChild);
74 beforeChild = nullptr;
75 return cell;
76 }
77 }
78 }
79 }
80 auto newCell = RenderTableCell::createAnonymousWithParentRenderer(parent);
81 auto& cell = *newCell;
82 m_builder.attach(parent, WTFMove(newCell), beforeChild);
83 beforeChild = nullptr;
84 return cell;
85}
86
87RenderElement& RenderTreeBuilder::Table::findOrCreateParentForChild(RenderTableSection& parent, const RenderObject& child, RenderObject*& beforeChild)
88{
89 if (is<RenderTableRow>(child))
90 return parent;
91
92 auto* lastChild = beforeChild ? beforeChild : parent.lastRow();
93 if (is<RenderTableRow>(lastChild) && lastChild->isAnonymous() && !lastChild->isBeforeOrAfterContent()) {
94 if (beforeChild == lastChild)
95 beforeChild = downcast<RenderTableRow>(*lastChild).firstCell();
96 return downcast<RenderElement>(*lastChild);
97 }
98
99 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == &parent) {
100 auto* row = beforeChild->previousSibling();
101 if (is<RenderTableRow>(row) && row->isAnonymous()) {
102 beforeChild = nullptr;
103 return downcast<RenderElement>(*row);
104 }
105 }
106
107 // If beforeChild is inside an anonymous cell/row, insert into the cell or into
108 // the anonymous row containing it, if there is one.
109 auto* parentCandidate = lastChild;
110 while (parentCandidate && parentCandidate->parent()->isAnonymous() && !is<RenderTableRow>(*parentCandidate))
111 parentCandidate = parentCandidate->parent();
112 if (is<RenderTableRow>(parentCandidate) && parentCandidate->isAnonymous() && !parentCandidate->isBeforeOrAfterContent())
113 return downcast<RenderElement>(*parentCandidate);
114
115 auto newRow = RenderTableRow::createAnonymousWithParentRenderer(parent);
116 auto& row = *newRow;
117 m_builder.attach(parent, WTFMove(newRow), beforeChild);
118 beforeChild = nullptr;
119 return row;
120}
121
122RenderElement& RenderTreeBuilder::Table::findOrCreateParentForChild(RenderTable& parent, const RenderObject& child, RenderObject*& beforeChild)
123{
124 if (is<RenderTableCaption>(child) || is<RenderTableCol>(child) || is<RenderTableSection>(child))
125 return parent;
126
127 auto* lastChild = parent.lastChild();
128 if (!beforeChild && is<RenderTableSection>(lastChild) && lastChild->isAnonymous() && !lastChild->isBeforeContent())
129 return downcast<RenderElement>(*lastChild);
130
131 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == &parent) {
132 auto* section = beforeChild->previousSibling();
133 if (is<RenderTableSection>(section) && section->isAnonymous()) {
134 beforeChild = nullptr;
135 return downcast<RenderElement>(*section);
136 }
137 }
138
139 auto* parentCandidate = beforeChild;
140 while (parentCandidate && parentCandidate->parent()->isAnonymous()
141 && !is<RenderTableSection>(*parentCandidate)
142 && parentCandidate->style().display() != DisplayType::TableCaption
143 && parentCandidate->style().display() != DisplayType::TableColumnGroup)
144 parentCandidate = parentCandidate->parent();
145
146 if (parentCandidate && is<RenderTableSection>(*parentCandidate) && parentCandidate->isAnonymous() && !parent.isAfterContent(parentCandidate)) {
147 if (beforeChild == parentCandidate)
148 beforeChild = downcast<RenderTableSection>(*parentCandidate).firstRow();
149 return downcast<RenderElement>(*parentCandidate);
150 }
151
152 if (beforeChild && !is<RenderTableSection>(*beforeChild)
153 && beforeChild->style().display() != DisplayType::TableCaption
154 && beforeChild->style().display() != DisplayType::TableColumnGroup)
155 beforeChild = nullptr;
156
157 auto newSection = RenderTableSection::createAnonymousWithParentRenderer(parent);
158 auto& section = *newSection;
159 m_builder.attach(parent, WTFMove(newSection), beforeChild);
160 beforeChild = nullptr;
161 return section;
162}
163
164void RenderTreeBuilder::Table::attach(RenderTableRow& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
165{
166 if (beforeChild && beforeChild->parent() != &parent)
167 beforeChild = m_builder.splitAnonymousBoxesAroundChild(parent, *beforeChild);
168
169 auto& newChild = *child.get();
170 ASSERT(!beforeChild || is<RenderTableCell>(*beforeChild));
171 m_builder.attachToRenderElement(parent, WTFMove(child), beforeChild);
172 // FIXME: child should always be a RenderTableCell at this point.
173 if (is<RenderTableCell>(newChild))
174 parent.didInsertTableCell(downcast<RenderTableCell>(newChild), beforeChild);
175}
176
177void RenderTreeBuilder::Table::attach(RenderTableSection& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
178{
179 if (beforeChild && beforeChild->parent() != &parent)
180 beforeChild = m_builder.splitAnonymousBoxesAroundChild(parent, *beforeChild);
181
182 // FIXME: child should always be a RenderTableRow at this point.
183 if (is<RenderTableRow>(*child.get()))
184 parent.willInsertTableRow(downcast<RenderTableRow>(*child.get()), beforeChild);
185 ASSERT(!beforeChild || is<RenderTableRow>(*beforeChild));
186 m_builder.attachToRenderElement(parent, WTFMove(child), beforeChild);
187}
188
189void RenderTreeBuilder::Table::attach(RenderTable& parent, RenderPtr<RenderObject> child, RenderObject* beforeChild)
190{
191 if (beforeChild && beforeChild->parent() != &parent)
192 beforeChild = m_builder.splitAnonymousBoxesAroundChild(parent, *beforeChild);
193
194 auto& newChild = *child.get();
195 if (is<RenderTableSection>(newChild))
196 parent.willInsertTableSection(downcast<RenderTableSection>(newChild), beforeChild);
197 else if (is<RenderTableCol>(newChild))
198 parent.willInsertTableColumn(downcast<RenderTableCol>(newChild), beforeChild);
199
200 m_builder.attachToRenderElement(parent, WTFMove(child), beforeChild);
201}
202
203bool RenderTreeBuilder::Table::childRequiresTable(const RenderElement& parent, const RenderObject& child)
204{
205 if (is<RenderTableCol>(child)) {
206 const RenderTableCol& newTableColumn = downcast<RenderTableCol>(child);
207 bool isColumnInColumnGroup = newTableColumn.isTableColumn() && is<RenderTableCol>(parent);
208 return !is<RenderTable>(parent) && !isColumnInColumnGroup;
209 }
210 if (is<RenderTableCaption>(child))
211 return !is<RenderTable>(parent);
212
213 if (is<RenderTableSection>(child))
214 return !is<RenderTable>(parent);
215
216 if (is<RenderTableRow>(child))
217 return !is<RenderTableSection>(parent);
218
219 if (is<RenderTableCell>(child))
220 return !is<RenderTableRow>(parent);
221
222 return false;
223}
224
225void RenderTreeBuilder::Table::collapseAndDestroyAnonymousSiblingRows(RenderTableRow& row)
226{
227 auto* section = row.section();
228 if (!section)
229 return;
230
231 // All siblings generated?
232 for (auto* current = section->firstRow(); current; current = current->nextRow()) {
233 if (current == &row)
234 continue;
235 if (!current->isAnonymous())
236 return;
237 }
238
239 RenderTableRow* rowToInsertInto = nullptr;
240 auto* currentRow = section->firstRow();
241 while (currentRow) {
242 if (currentRow == &row) {
243 currentRow = currentRow->nextRow();
244 continue;
245 }
246 if (!rowToInsertInto) {
247 rowToInsertInto = currentRow;
248 currentRow = currentRow->nextRow();
249 continue;
250 }
251 m_builder.moveAllChildren(*currentRow, *rowToInsertInto, RenderTreeBuilder::NormalizeAfterInsertion::No);
252 auto toDestroy = m_builder.detach(*section, *currentRow);
253 currentRow = currentRow->nextRow();
254 }
255 if (rowToInsertInto)
256 rowToInsertInto->setNeedsLayout();
257}
258
259}
260