Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / LayoutMultiColumnFlowThreadTest.cpp
blobede333842bfa8211751118a1209c0fd3124fabef
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "config.h"
7 #include "core/layout/LayoutMultiColumnFlowThread.h"
9 #include "core/layout/LayoutMultiColumnSet.h"
10 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
11 #include "core/layout/LayoutTestHelper.h"
13 #include <gtest/gtest.h>
15 namespace blink {
17 namespace {
19 class MultiColumnRenderingTest : public RenderingTest {
20 public:
21 LayoutMultiColumnFlowThread* findFlowThread(const char* id) const;
23 // Generate a signature string based on what kind of column boxes the flow thread has
24 // established. 'c' is used for regular column content sets, while 's' is used for spanners.
25 // '?' is used when there's an unknown box type (which should be considered a failure).
26 String columnSetSignature(LayoutMultiColumnFlowThread*);
27 String columnSetSignature(const char* multicolId);
29 void setMulticolHTML(const String&);
32 LayoutMultiColumnFlowThread* MultiColumnRenderingTest::findFlowThread(const char* id) const
34 Node* multicol = document().getElementById(id);
35 if (!multicol)
36 return nullptr;
37 LayoutBlockFlow* multicolContainer = toLayoutBlockFlow(multicol->layoutObject());
38 if (!multicolContainer)
39 return nullptr;
40 return multicolContainer->multiColumnFlowThread();
43 String MultiColumnRenderingTest::columnSetSignature(LayoutMultiColumnFlowThread* flowThread)
45 String signature = "";
46 for (LayoutBox* columnBox = flowThread->firstMultiColumnBox();
47 columnBox;
48 columnBox = columnBox->nextSiblingMultiColumnBox()) {
49 if (columnBox->isLayoutMultiColumnSpannerPlaceholder())
50 signature.append('s');
51 else if (columnBox->isLayoutMultiColumnSet())
52 signature.append('c');
53 else
54 signature.append('?');
56 return signature;
59 String MultiColumnRenderingTest::columnSetSignature(const char* multicolId)
61 return columnSetSignature(findFlowThread(multicolId));
64 void MultiColumnRenderingTest::setMulticolHTML(const String& html)
66 const char* style =
67 "<style>"
68 " #mc { -webkit-columns:2; }"
69 " .s, #spanner, #spanner1, #spanner2 { -webkit-column-span:all; }"
70 "</style>";
71 setBodyInnerHTML(style + html);
74 TEST_F(MultiColumnRenderingTest, OneBlockWithInDepthTreeStructureCheck)
76 // Examine the layout tree established by a simple multicol container with a block with some text inside.
77 setMulticolHTML("<div id='mc'><div>xxx</div></div>");
78 Node* multicol = document().getElementById("mc");
79 ASSERT_TRUE(multicol);
80 LayoutBlockFlow* multicolContainer = toLayoutBlockFlow(multicol->layoutObject());
81 ASSERT_TRUE(multicolContainer);
82 LayoutMultiColumnFlowThread* flowThread = multicolContainer->multiColumnFlowThread();
83 ASSERT_TRUE(flowThread);
84 EXPECT_EQ(columnSetSignature(flowThread), "c");
85 EXPECT_EQ(flowThread->parent(), multicolContainer);
86 EXPECT_FALSE(flowThread->previousSibling());
87 LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet();
88 ASSERT_TRUE(columnSet);
89 EXPECT_EQ(columnSet->previousSibling(), flowThread);
90 EXPECT_FALSE(columnSet->nextSibling());
91 LayoutBlockFlow* block = toLayoutBlockFlow(flowThread->firstChild());
92 ASSERT_TRUE(block);
93 EXPECT_FALSE(block->nextSibling());
94 ASSERT_TRUE(block->firstChild());
95 EXPECT_TRUE(block->firstChild()->isText());
96 EXPECT_FALSE(block->firstChild()->nextSibling());
99 TEST_F(MultiColumnRenderingTest, Empty)
101 // If there's no column content, there should be no column set.
102 setMulticolHTML("<div id='mc'></div>");
103 EXPECT_EQ(columnSetSignature("mc"), "");
106 TEST_F(MultiColumnRenderingTest, OneBlock)
108 // There is some content, so we should create a column set.
109 setMulticolHTML("<div id='mc'><div id='block'></div></div>");
110 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
111 ASSERT_EQ(columnSetSignature(flowThread), "c");
112 LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet();
113 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("block")->layoutObject()), columnSet);
116 TEST_F(MultiColumnRenderingTest, TwoBlocks)
118 // No matter how much content, we should only create one column set (unless there are spanners).
119 setMulticolHTML("<div id='mc'><div id='block1'></div><div id='block2'></div></div>");
120 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
121 ASSERT_EQ(columnSetSignature(flowThread), "c");
122 LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet();
123 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("block1")->layoutObject()), columnSet);
124 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("block2")->layoutObject()), columnSet);
127 TEST_F(MultiColumnRenderingTest, Spanner)
129 // With one spanner and no column content, we should create a spanner set.
130 setMulticolHTML("<div id='mc'><div id='spanner'></div></div>");
131 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
132 ASSERT_EQ(columnSetSignature(flowThread), "s");
133 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
134 EXPECT_EQ(flowThread->firstMultiColumnSet(), nullptr);
135 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
136 EXPECT_EQ(document().getElementById("spanner")->layoutObject()->spannerPlaceholder(), columnBox);
139 TEST_F(MultiColumnRenderingTest, ContentThenSpanner)
141 // With some column content followed by a spanner, we need a column set followed by a spanner set.
142 setMulticolHTML("<div id='mc'><div id='columnContent'></div><div id='spanner'></div></div>");
143 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
144 ASSERT_EQ(columnSetSignature(flowThread), "cs");
145 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
146 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("columnContent")->layoutObject()), columnBox);
147 columnBox = columnBox->nextSiblingMultiColumnBox();
148 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
149 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("columnContent")->layoutObject()), nullptr);
152 TEST_F(MultiColumnRenderingTest, SpannerThenContent)
154 // With a spanner followed by some column content, we need a spanner set followed by a column set.
155 setMulticolHTML("<div id='mc'><div id='spanner'></div><div id='columnContent'></div></div>");
156 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
157 ASSERT_EQ(columnSetSignature(flowThread), "sc");
158 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
159 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
160 columnBox = columnBox->nextSiblingMultiColumnBox();
161 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("columnContent")->layoutObject()), columnBox);
162 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("columnContent")->layoutObject()), nullptr);
165 TEST_F(MultiColumnRenderingTest, ContentThenSpannerThenContent)
167 // With column content followed by a spanner followed by some column content, we need a column
168 // set followed by a spanner set followed by a column set.
169 setMulticolHTML("<div id='mc'><div id='columnContentBefore'></div><div id='spanner'></div><div id='columnContentAfter'></div></div>");
170 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
171 ASSERT_EQ(columnSetSignature(flowThread), "csc");
172 LayoutBox* columnBox = flowThread->firstMultiColumnSet();
173 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("columnContentBefore")->layoutObject()), columnBox);
174 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("columnContentBefore")->layoutObject()), nullptr);
175 columnBox = columnBox->nextSiblingMultiColumnBox();
176 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
177 columnBox = columnBox->nextSiblingMultiColumnBox();
178 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("columnContentAfter")->layoutObject()), columnBox);
179 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("columnContentAfter")->layoutObject()), nullptr);
182 TEST_F(MultiColumnRenderingTest, TwoSpanners)
184 // With two spanners and no column content, we need two spanner sets.
185 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='spanner2'></div></div>");
186 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
187 ASSERT_EQ(columnSetSignature(flowThread), "ss");
188 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
189 EXPECT_EQ(flowThread->firstMultiColumnSet(), nullptr);
190 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner1")->layoutObject()), columnBox);
191 EXPECT_EQ(document().getElementById("spanner1")->layoutObject()->spannerPlaceholder(), columnBox);
192 columnBox = columnBox->nextSiblingMultiColumnBox();
193 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner2")->layoutObject()), columnBox);
194 EXPECT_EQ(document().getElementById("spanner2")->layoutObject()->spannerPlaceholder(), columnBox);
197 TEST_F(MultiColumnRenderingTest, SpannerThenContentThenSpanner)
199 // With two spanners and some column content in-between, we need a spanner set, a column set and another spanner set.
200 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='columnContent'></div><div id='spanner2'></div></div>");
201 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
202 ASSERT_EQ(columnSetSignature(flowThread), "scs");
203 LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet();
204 EXPECT_EQ(columnSet->nextSiblingMultiColumnSet(), nullptr);
205 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
206 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner1")->layoutObject()), columnBox);
207 columnBox = columnBox->nextSiblingMultiColumnBox();
208 EXPECT_EQ(columnBox, columnSet);
209 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("columnContent")->layoutObject()), columnSet);
210 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("columnContent")->layoutObject()), nullptr);
211 columnBox = columnBox->nextSiblingMultiColumnBox();
212 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner2")->layoutObject()), columnBox);
215 TEST_F(MultiColumnRenderingTest, SpannerWithSpanner)
217 // column-span:all on something inside column-span:all has no effect.
218 setMulticolHTML("<div id='mc'><div id='spanner'><div id='invalidSpanner' class='s'></div></div></div>");
219 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
220 ASSERT_EQ(columnSetSignature(flowThread), "s");
221 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
222 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
223 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("invalidSpanner")->layoutObject()), columnBox);
224 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner")->layoutObject());
225 EXPECT_EQ(document().getElementById("spanner")->layoutObject()->spannerPlaceholder(), columnBox);
226 EXPECT_EQ(document().getElementById("invalidSpanner")->layoutObject()->spannerPlaceholder(), nullptr);
229 TEST_F(MultiColumnRenderingTest, SubtreeWithSpanner)
231 setMulticolHTML("<div id='mc'><div id='outer'><div id='block1'></div><div id='spanner'></div><div id='block2'></div></div></div>");
232 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
233 EXPECT_EQ(columnSetSignature(flowThread), "csc");
234 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
235 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("outer")->layoutObject()), columnBox);
236 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("block1")->layoutObject()), columnBox);
237 columnBox = columnBox->nextSiblingMultiColumnBox();
238 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner")->layoutObject()), columnBox);
239 EXPECT_EQ(document().getElementById("spanner")->layoutObject()->spannerPlaceholder(), columnBox);
240 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner")->layoutObject());
241 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("outer")->layoutObject()), nullptr);
242 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("block1")->layoutObject()), nullptr);
243 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("block2")->layoutObject()), nullptr);
244 columnBox = columnBox->nextSiblingMultiColumnBox();
245 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("block2")->layoutObject()), columnBox);
248 TEST_F(MultiColumnRenderingTest, SubtreeWithSpannerAfterSpanner)
250 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='outer'>text<div id='spanner2'></div><div id='after'></div></div></div>");
251 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
252 EXPECT_EQ(columnSetSignature(flowThread), "scsc");
253 LayoutBox* columnBox = flowThread->firstMultiColumnBox();
254 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner1")->layoutObject()), columnBox);
255 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner1")->layoutObject());
256 EXPECT_EQ(document().getElementById("spanner1")->layoutObject()->spannerPlaceholder(), columnBox);
257 columnBox = columnBox->nextSiblingMultiColumnBox();
258 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("outer")->layoutObject()), columnBox);
259 columnBox = columnBox->nextSiblingMultiColumnBox();
260 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner2")->layoutObject()), columnBox);
261 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner2")->layoutObject());
262 EXPECT_EQ(document().getElementById("spanner2")->layoutObject()->spannerPlaceholder(), columnBox);
263 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("outer")->layoutObject()), nullptr);
264 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("after")->layoutObject()), nullptr);
265 columnBox = columnBox->nextSiblingMultiColumnBox();
266 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("after")->layoutObject()), columnBox);
269 TEST_F(MultiColumnRenderingTest, SubtreeWithSpannerBeforeSpanner)
271 setMulticolHTML("<div id='mc'><div id='outer'>text<div id='spanner1'></div>text</div><div id='spanner2'></div></div>");
272 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
273 EXPECT_EQ(columnSetSignature(flowThread), "cscs");
274 LayoutBox* columnBox = flowThread->firstMultiColumnSet();
275 EXPECT_EQ(flowThread->mapDescendantToColumnSet(document().getElementById("outer")->layoutObject()), columnBox);
276 columnBox = columnBox->nextSiblingMultiColumnBox();
277 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner1")->layoutObject()), columnBox);
278 EXPECT_EQ(document().getElementById("spanner1")->layoutObject()->spannerPlaceholder(), columnBox);
279 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner1")->layoutObject());
280 columnBox = columnBox->nextSiblingMultiColumnBox()->nextSiblingMultiColumnBox();
281 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("spanner2")->layoutObject()), columnBox);
282 EXPECT_EQ(document().getElementById("spanner2")->layoutObject()->spannerPlaceholder(), columnBox);
283 EXPECT_EQ(toLayoutMultiColumnSpannerPlaceholder(columnBox)->layoutObjectInFlowThread(), document().getElementById("spanner2")->layoutObject());
284 EXPECT_EQ(flowThread->containingColumnSpannerPlaceholder(document().getElementById("outer")->layoutObject()), nullptr);
287 TEST_F(MultiColumnRenderingTest, columnSetAtBlockOffset)
289 setMulticolHTML("<div id='mc' style='line-height:100px;'>text<br>text<br>text<br>text<br>text<div id='spanner1'>spanner</div>text<br>text<div id='spanner2'>text<br>text</div>text</div>");
290 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
291 EXPECT_EQ(columnSetSignature(flowThread), "cscsc");
292 LayoutMultiColumnSet* firstRow = flowThread->firstMultiColumnSet();
293 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(-10000)), firstRow); // negative overflow
294 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit()), firstRow);
295 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(499)), firstRow); // bottom of last line in first row.
296 LayoutMultiColumnSet* secondRow = firstRow->nextSiblingMultiColumnSet();
297 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(500)), secondRow);
298 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(699)), secondRow);
299 LayoutMultiColumnSet* thirdRow = secondRow->nextSiblingMultiColumnSet();
300 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(700)), thirdRow);
301 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(799)), thirdRow); // bottom of last row
302 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(10000)), thirdRow); // overflow
305 TEST_F(MultiColumnRenderingTest, columnSetAtBlockOffsetVerticalRl)
307 setMulticolHTML("<div id='mc' style='line-height:100px; -webkit-writing-mode:vertical-rl;'>text<br>text<br>text<br>text<br>text<div id='spanner1'>spanner</div>text<br>text<div id='spanner2'>text<br>text</div>text</div>");
308 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
309 EXPECT_EQ(columnSetSignature(flowThread), "cscsc");
310 LayoutMultiColumnSet* firstRow = flowThread->firstMultiColumnSet();
311 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(-10000)), firstRow); // negative overflow
312 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit()), firstRow);
313 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(499)), firstRow); // bottom of last line in first row.
314 LayoutMultiColumnSet* secondRow = firstRow->nextSiblingMultiColumnSet();
315 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(500)), secondRow);
316 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(699)), secondRow);
317 LayoutMultiColumnSet* thirdRow = secondRow->nextSiblingMultiColumnSet();
318 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(700)), thirdRow);
319 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(799)), thirdRow); // bottom of last row
320 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(10000)), thirdRow); // overflow
323 TEST_F(MultiColumnRenderingTest, columnSetAtBlockOffsetVerticalLr)
325 setMulticolHTML("<div id='mc' style='line-height:100px; -webkit-writing-mode:vertical-lr;'>text<br>text<br>text<br>text<br>text<div id='spanner1'>spanner</div>text<br>text<div id='spanner2'>text<br>text</div>text</div>");
326 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
327 EXPECT_EQ(columnSetSignature(flowThread), "cscsc");
328 LayoutMultiColumnSet* firstRow = flowThread->firstMultiColumnSet();
329 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(-10000)), firstRow); // negative overflow
330 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit()), firstRow);
331 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(499)), firstRow); // bottom of last line in first row.
332 LayoutMultiColumnSet* secondRow = firstRow->nextSiblingMultiColumnSet();
333 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(500)), secondRow);
334 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(699)), secondRow);
335 LayoutMultiColumnSet* thirdRow = secondRow->nextSiblingMultiColumnSet();
336 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(700)), thirdRow);
337 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(799)), thirdRow); // bottom of last row
338 EXPECT_EQ(flowThread->columnSetAtBlockOffset(LayoutUnit(10000)), thirdRow); // overflow
341 class MultiColumnTreeModifyingTest : public MultiColumnRenderingTest {
342 public:
343 void setMulticolHTML(const char*);
344 void reparentLayoutObject(const char* newParentId, const char* childId, const char* insertBeforeId = nullptr);
345 void destroyLayoutObject(LayoutObject* child);
346 void destroyLayoutObject(const char* childId);
349 void MultiColumnTreeModifyingTest::setMulticolHTML(const char* html)
351 MultiColumnRenderingTest::setMulticolHTML(html);
352 // Allow modifications to the layout tree structure, because that's what we want to test.
353 document().lifecycle().advanceTo(DocumentLifecycle::InStyleRecalc);
356 void MultiColumnTreeModifyingTest::reparentLayoutObject(const char* newParentId, const char* childId, const char* insertBeforeId)
358 LayoutObject* newParent = document().getElementById(newParentId)->layoutObject();
359 LayoutObject* child = document().getElementById(childId)->layoutObject();
360 LayoutObject* insertBefore = insertBeforeId ? document().getElementById(insertBeforeId)->layoutObject() : nullptr;
361 child->remove();
362 newParent->addChild(child, insertBefore);
365 void MultiColumnTreeModifyingTest::destroyLayoutObject(LayoutObject* child)
367 // Remove and destroy in separate steps, so that we get to test removal of subtrees.
368 child->remove();
369 child->node()->detach();
372 void MultiColumnTreeModifyingTest::destroyLayoutObject(const char* childId)
374 destroyLayoutObject(document().getElementById(childId)->layoutObject());
377 TEST_F(MultiColumnTreeModifyingTest, InsertFirstContentAndRemove)
379 setMulticolHTML("<div id='block'></div><div id='mc'></div>");
380 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
381 LayoutBlockFlow* block = toLayoutBlockFlow(document().getElementById("block")->layoutObject());
382 LayoutBlockFlow* multicolContainer = toLayoutBlockFlow(document().getElementById("mc")->layoutObject());
383 block->remove();
384 multicolContainer->addChild(block);
385 EXPECT_EQ(block->parent(), flowThread);
386 // A set should have appeared, now that the multicol container has content.
387 EXPECT_EQ(columnSetSignature(flowThread), "c");
389 destroyLayoutObject(block);
390 // The set should be gone again now, since there's nothing inside the multicol container anymore.
391 EXPECT_EQ(columnSetSignature("mc"), "");
394 TEST_F(MultiColumnTreeModifyingTest, InsertContentBeforeContentAndRemove)
396 setMulticolHTML("<div id='block'></div><div id='mc'><div id='insertBefore'></div></div>");
397 EXPECT_EQ(columnSetSignature("mc"), "c");
398 reparentLayoutObject("mc", "block", "insertBefore");
399 // There was already some content prior to our insertion, so no new set should be inserted.
400 EXPECT_EQ(columnSetSignature("mc"), "c");
401 destroyLayoutObject("block");
402 // There's still some content after the removal, so the set should remain.
403 EXPECT_EQ(columnSetSignature("mc"), "c");
406 TEST_F(MultiColumnTreeModifyingTest, InsertContentAfterContentAndRemove)
408 setMulticolHTML("<div id='block'></div><div id='mc'><div></div></div>");
409 EXPECT_EQ(columnSetSignature("mc"), "c");
410 reparentLayoutObject("mc", "block");
411 // There was already some content prior to our insertion, so no new set should be inserted.
412 EXPECT_EQ(columnSetSignature("mc"), "c");
413 destroyLayoutObject("block");
414 // There's still some content after the removal, so the set should remain.
415 EXPECT_EQ(columnSetSignature("mc"), "c");
418 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerAndRemove)
420 setMulticolHTML("<div id='spanner'></div><div id='mc'></div>");
421 LayoutMultiColumnFlowThread* flowThread = findFlowThread("mc");
422 LayoutBlockFlow* spanner = toLayoutBlockFlow(document().getElementById("spanner")->layoutObject());
423 LayoutBlockFlow* multicolContainer = toLayoutBlockFlow(document().getElementById("mc")->layoutObject());
424 spanner->remove();
425 multicolContainer->addChild(spanner);
426 EXPECT_EQ(spanner->parent(), flowThread);
427 // We should now have a spanner placeholder, since we just moved a spanner into the multicol container.
428 EXPECT_EQ(columnSetSignature(flowThread), "s");
429 destroyLayoutObject(spanner);
430 EXPECT_EQ(columnSetSignature(flowThread), "");
433 TEST_F(MultiColumnTreeModifyingTest, InsertTwoSpannersAndRemove)
435 setMulticolHTML("<div id='block'>ee<div class='s'></div><div class='s'></div></div><div id='mc'></div>");
436 reparentLayoutObject("mc", "block");
437 EXPECT_EQ(columnSetSignature("mc"), "css");
438 destroyLayoutObject("block");
439 EXPECT_EQ(columnSetSignature("mc"), "");
442 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerAfterContentAndRemove)
444 setMulticolHTML("<div id='spanner'></div><div id='mc'><div></div></div>");
445 reparentLayoutObject("mc", "spanner");
446 // We should now have a spanner placeholder, since we just moved a spanner into the multicol container.
447 EXPECT_EQ(columnSetSignature("mc"), "cs");
448 destroyLayoutObject("spanner");
449 EXPECT_EQ(columnSetSignature("mc"), "c");
452 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerBeforeContentAndRemove)
454 setMulticolHTML("<div id='spanner'></div><div id='mc'><div id='columnContent'></div></div>");
455 reparentLayoutObject("mc", "spanner", "columnContent");
456 // We should now have a spanner placeholder, since we just moved a spanner into the multicol container.
457 EXPECT_EQ(columnSetSignature("mc"), "sc");
458 destroyLayoutObject("spanner");
459 EXPECT_EQ(columnSetSignature("mc"), "c");
462 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerBetweenContentAndRemove)
464 setMulticolHTML("<div id='spanner'></div><div id='mc'><div></div><div id='insertBefore'></div></div>");
465 reparentLayoutObject("mc", "spanner", "insertBefore");
466 // Since the spanner was inserted in the middle of column content, what used to be one column
467 // set had to be split in two, in order to get a spot to insert the spanner placeholder.
468 EXPECT_EQ(columnSetSignature("mc"), "csc");
469 destroyLayoutObject("spanner");
470 // The spanner placeholder should be gone again now, and the two sets be merged into one.
471 EXPECT_EQ(columnSetSignature("mc"), "c");
474 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithContentAndSpannerAndRemove)
476 setMulticolHTML("<div id='block'>text<div id='spanner'></div>text</div><div id='mc'></div>");
477 reparentLayoutObject("mc", "block");
478 EXPECT_EQ(columnSetSignature("mc"), "csc");
479 destroyLayoutObject("block");
480 EXPECT_EQ(columnSetSignature("mc"), "");
483 TEST_F(MultiColumnTreeModifyingTest, InsertInsideSpannerAndRemove)
485 setMulticolHTML("<div id='block'>text</div><div id='mc'><div id='spanner'></div></div>");
486 reparentLayoutObject("spanner", "block");
487 EXPECT_EQ(columnSetSignature("mc"), "s");
488 destroyLayoutObject("block");
489 EXPECT_EQ(columnSetSignature("mc"), "s");
492 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerInContentBeforeSpannerAndRemove)
494 setMulticolHTML("<div id='spanner'></div><div id='mc'><div></div><div id='insertBefore'></div><div class='s'></div></div>");
495 EXPECT_EQ(columnSetSignature("mc"), "cs");
496 reparentLayoutObject("mc", "spanner", "insertBefore");
497 EXPECT_EQ(columnSetSignature("mc"), "cscs");
498 destroyLayoutObject("spanner");
499 EXPECT_EQ(columnSetSignature("mc"), "cs");
502 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerInContentAfterSpannerAndRemove)
504 setMulticolHTML("<div id='spanner'></div><div id='mc'><div class='s'></div><div></div><div id='insertBefore'></div></div>");
505 EXPECT_EQ(columnSetSignature("mc"), "sc");
506 reparentLayoutObject("mc", "spanner", "insertBefore");
507 EXPECT_EQ(columnSetSignature("mc"), "scsc");
508 destroyLayoutObject("spanner");
509 EXPECT_EQ(columnSetSignature("mc"), "sc");
512 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerAfterSpannerAndRemove)
514 setMulticolHTML("<div id='spanner'></div><div id='mc'><div class='s'></div></div>");
515 reparentLayoutObject("mc", "spanner");
516 EXPECT_EQ(columnSetSignature("mc"), "ss");
517 destroyLayoutObject("spanner");
518 EXPECT_EQ(columnSetSignature("mc"), "s");
521 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerBeforeSpannerAndRemove)
523 setMulticolHTML("<div id='spanner'></div><div id='mc'><div id='insertBefore' class='s'></div></div>");
524 reparentLayoutObject("mc", "spanner", "insertBefore");
525 EXPECT_EQ(columnSetSignature("mc"), "ss");
526 destroyLayoutObject("spanner");
527 EXPECT_EQ(columnSetSignature("mc"), "s");
530 TEST_F(MultiColumnTreeModifyingTest, InsertContentBeforeSpannerAndRemove)
532 setMulticolHTML("<div id='block'></div><div id='mc'><div id='insertBefore' class='s'></div></div>");
533 reparentLayoutObject("mc", "block", "insertBefore");
534 EXPECT_EQ(columnSetSignature("mc"), "cs");
535 destroyLayoutObject("block");
536 EXPECT_EQ(columnSetSignature("mc"), "s");
539 TEST_F(MultiColumnTreeModifyingTest, InsertContentAfterContentBeforeSpannerAndRemove)
541 setMulticolHTML("<div id='block'></div><div id='mc'>text<div id='insertBefore' class='s'></div></div>");
542 EXPECT_EQ(columnSetSignature("mc"), "cs");
543 reparentLayoutObject("mc", "block", "insertBefore");
544 // There was already some content before the spanner prior to our insertion, so no new set
545 // should be inserted.
546 EXPECT_EQ(columnSetSignature("mc"), "cs");
547 destroyLayoutObject("block");
548 EXPECT_EQ(columnSetSignature("mc"), "cs");
551 TEST_F(MultiColumnTreeModifyingTest, InsertContentAfterContentAndSpannerAndRemove)
553 setMulticolHTML("<div id='block'></div><div id='mc'>content<div class='s'></div></div>");
554 EXPECT_EQ(columnSetSignature("mc"), "cs");
555 reparentLayoutObject("mc", "block");
556 EXPECT_EQ(columnSetSignature("mc"), "csc");
557 destroyLayoutObject("block");
558 EXPECT_EQ(columnSetSignature("mc"), "cs");
561 TEST_F(MultiColumnTreeModifyingTest, InsertContentBeforeSpannerAndContentAndRemove)
563 setMulticolHTML("<div id='block'></div><div id='mc'><div id='insertBefore' class='s'></div>content</div>");
564 EXPECT_EQ(columnSetSignature("mc"), "sc");
565 reparentLayoutObject("mc", "block", "insertBefore");
566 EXPECT_EQ(columnSetSignature("mc"), "csc");
567 destroyLayoutObject("block");
568 EXPECT_EQ(columnSetSignature("mc"), "sc");
571 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerIntoContentBeforeSpannerAndRemove)
573 setMulticolHTML("<div id='spanner'></div><div id='mc'><div></div><div id='insertBefore'></div><div class='s'></div><div class='s'></div><div></div></div>");
574 EXPECT_EQ(columnSetSignature("mc"), "cssc");
575 reparentLayoutObject("mc", "spanner", "insertBefore");
576 EXPECT_EQ(columnSetSignature("mc"), "cscssc");
577 destroyLayoutObject("spanner");
578 EXPECT_EQ(columnSetSignature("mc"), "cssc");
581 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerIntoContentAfterSpannerAndRemove)
583 setMulticolHTML("<div id='spanner'></div><div id='mc'><div></div><div class='s'></div><div class='s'></div><div></div><div id='insertBefore'></div></div>");
584 EXPECT_EQ(columnSetSignature("mc"), "cssc");
585 reparentLayoutObject("mc", "spanner", "insertBefore");
586 EXPECT_EQ(columnSetSignature("mc"), "csscsc");
587 destroyLayoutObject("spanner");
588 EXPECT_EQ(columnSetSignature("mc"), "cssc");
591 TEST_F(MultiColumnTreeModifyingTest, InsertInvalidSpannerAndRemove)
593 setMulticolHTML("<div class='s' id='invalidSpanner'></div><div id='mc'><div id='spanner'></div></div>");
594 EXPECT_EQ(columnSetSignature("mc"), "s");
595 reparentLayoutObject("spanner", "invalidSpanner");
596 // It's not allowed to nest spanners.
597 EXPECT_EQ(columnSetSignature("mc"), "s");
598 destroyLayoutObject("invalidSpanner");
599 EXPECT_EQ(columnSetSignature("mc"), "s");
602 TEST_F(MultiColumnTreeModifyingTest, InsertSpannerWithInvalidSpannerAndRemove)
604 setMulticolHTML("<div id='spanner'><div class='s' id='invalidSpanner'></div></div><div id='mc'></div>");
605 reparentLayoutObject("mc", "spanner");
606 // It's not allowed to nest spanners.
607 EXPECT_EQ(columnSetSignature("mc"), "s");
608 destroyLayoutObject("spanner");
609 EXPECT_EQ(columnSetSignature("mc"), "");
612 TEST_F(MultiColumnTreeModifyingTest, InsertInvalidSpannerInSpannerBetweenContentAndRemove)
614 setMulticolHTML("<div class='s' id='invalidSpanner'></div><div id='mc'>text<div id='spanner'></div>text</div>");
615 EXPECT_EQ(columnSetSignature("mc"), "csc");
616 reparentLayoutObject("spanner", "invalidSpanner");
617 EXPECT_EQ(columnSetSignature("mc"), "csc");
618 destroyLayoutObject("invalidSpanner");
619 EXPECT_EQ(columnSetSignature("mc"), "csc");
622 TEST_F(MultiColumnTreeModifyingTest, InsertContentAndSpannerAndRemove)
624 setMulticolHTML("<div id='block'>text<div id='spanner'></div></div><div id='mc'>text</div>");
625 reparentLayoutObject("mc", "block");
626 EXPECT_EQ(columnSetSignature("mc"), "cs");
627 destroyLayoutObject("block");
628 EXPECT_EQ(columnSetSignature("mc"), "c");
631 TEST_F(MultiColumnTreeModifyingTest, InsertContentAndSpannerAndContentAndRemove)
633 setMulticolHTML("<div id='block'><div id='spanner'></div>text</div><div id='mc'></div>");
634 reparentLayoutObject("mc", "block");
635 EXPECT_EQ(columnSetSignature("mc"), "csc");
636 destroyLayoutObject("block");
637 EXPECT_EQ(columnSetSignature("mc"), "");
640 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerAndRemove)
642 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'></div>");
643 reparentLayoutObject("mc", "block");
644 EXPECT_EQ(columnSetSignature("mc"), "csc");
645 destroyLayoutObject("block");
646 EXPECT_EQ(columnSetSignature("mc"), "");
649 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerAfterContentAndRemove)
651 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'>column content</div>");
652 reparentLayoutObject("mc", "block");
653 EXPECT_EQ(columnSetSignature("mc"), "csc");
654 destroyLayoutObject("block");
655 EXPECT_EQ(columnSetSignature("mc"), "c");
658 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerBeforeContentAndRemove)
660 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'><div id='insertBefore'>column content</div></div>");
661 reparentLayoutObject("mc", "block", "insertBefore");
662 EXPECT_EQ(columnSetSignature("mc"), "csc");
663 destroyLayoutObject("block");
664 EXPECT_EQ(columnSetSignature("mc"), "c");
667 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerInsideContentAndRemove)
669 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'><div>outside<div id='insertBefore'>outside</div></div></div>");
670 EXPECT_EQ(columnSetSignature("mc"), "c");
671 reparentLayoutObject("mc", "block", "insertBefore");
672 EXPECT_EQ(columnSetSignature("mc"), "csc");
673 destroyLayoutObject("block");
674 EXPECT_EQ(columnSetSignature("mc"), "c");
677 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerAfterSpannerAndRemove)
679 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'><div class='s'></div></div>");
680 EXPECT_EQ(columnSetSignature("mc"), "s");
681 reparentLayoutObject("mc", "block");
682 EXPECT_EQ(columnSetSignature("mc"), "scsc");
683 destroyLayoutObject("block");
684 EXPECT_EQ(columnSetSignature("mc"), "s");
687 TEST_F(MultiColumnTreeModifyingTest, InsertSubtreeWithSpannerBeforeSpannerAndRemove)
689 setMulticolHTML("<div id='block'>text<div class='s'></div>text</div><div id='mc'><div id='insertBefore' class='s'></div></div>");
690 EXPECT_EQ(columnSetSignature("mc"), "s");
691 reparentLayoutObject("mc", "block", "insertBefore");
692 EXPECT_EQ(columnSetSignature("mc"), "cscs");
693 destroyLayoutObject("block");
694 EXPECT_EQ(columnSetSignature("mc"), "s");
697 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndContent)
699 setMulticolHTML("<div id='mc'><div id='block'>text<div class='s'></div>text</div></div>");
700 EXPECT_EQ(columnSetSignature("mc"), "csc");
701 destroyLayoutObject("block");
702 EXPECT_EQ(columnSetSignature("mc"), "");
705 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndSomeContentBefore)
707 setMulticolHTML("<div id='mc'>text<div id='block'>text<div class='s'></div></div></div>");
708 EXPECT_EQ(columnSetSignature("mc"), "cs");
709 destroyLayoutObject("block");
710 EXPECT_EQ(columnSetSignature("mc"), "c");
713 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndAllContentBefore)
715 setMulticolHTML("<div id='mc'><div id='block'>text<div class='s'></div></div></div>");
716 EXPECT_EQ(columnSetSignature("mc"), "cs");
717 destroyLayoutObject("block");
718 EXPECT_EQ(columnSetSignature("mc"), "");
721 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndAllContentBeforeWithContentAfter)
723 setMulticolHTML("<div id='mc'><div id='block'>text<div class='s'></div></div>text</div>");
724 EXPECT_EQ(columnSetSignature("mc"), "csc");
725 destroyLayoutObject("block");
726 EXPECT_EQ(columnSetSignature("mc"), "c");
729 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndSomeContentAfter)
731 setMulticolHTML("<div id='mc'><div id='block'><div class='s'></div>text</div>text</div>");
732 EXPECT_EQ(columnSetSignature("mc"), "csc");
733 destroyLayoutObject("block");
734 EXPECT_EQ(columnSetSignature("mc"), "c");
737 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndAllContentAfter)
739 setMulticolHTML("<div id='mc'><div id='block'><div class='s'></div>text</div></div>");
740 EXPECT_EQ(columnSetSignature("mc"), "csc");
741 destroyLayoutObject("block");
742 EXPECT_EQ(columnSetSignature("mc"), "");
745 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndAllContentAfterWithContentBefore)
747 setMulticolHTML("<div id='mc'>text<div id='block'><div class='s'></div>text</div></div>");
748 EXPECT_EQ(columnSetSignature("mc"), "csc");
749 destroyLayoutObject("block");
750 EXPECT_EQ(columnSetSignature("mc"), "c");
753 TEST_F(MultiColumnTreeModifyingTest, RemoveTwoSpannersBeforeContent)
755 setMulticolHTML("<div id='mc'><div id='block'><div class='s'></div><div class='s'></div></div>text</div>");
756 EXPECT_EQ(columnSetSignature("mc"), "cssc");
757 destroyLayoutObject("block");
758 EXPECT_EQ(columnSetSignature("mc"), "c");
761 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndContentAndSpanner)
763 setMulticolHTML("<div id='mc'><div id='block'><div class='s'></div>text<div class='s'></div>text</div></div>");
764 EXPECT_EQ(columnSetSignature("mc"), "cscsc");
765 destroyLayoutObject("block");
766 EXPECT_EQ(columnSetSignature("mc"), "");
769 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndContentAndSpannerBeforeContent)
771 setMulticolHTML("<div id='mc'><div id='block'><div class='s'></div>text<div class='s'></div></div>text</div>");
772 EXPECT_EQ(columnSetSignature("mc"), "cscsc");
773 destroyLayoutObject("block");
774 EXPECT_EQ(columnSetSignature("mc"), "c");
777 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerAndContentAndSpannerAfterContent)
779 setMulticolHTML("<div id='mc'>text<div id='block'><div class='s'></div>text<div class='s'></div></div></div>");
780 EXPECT_EQ(columnSetSignature("mc"), "cscs");
781 destroyLayoutObject("block");
782 EXPECT_EQ(columnSetSignature("mc"), "c");
785 TEST_F(MultiColumnTreeModifyingTest, RemoveInvalidSpannerInSpannerBetweenContent)
787 setMulticolHTML("<div id='mc'>text<div class='s'><div id='spanner'></div></div>text</div>");
788 EXPECT_EQ(columnSetSignature("mc"), "csc");
789 destroyLayoutObject("spanner");
790 EXPECT_EQ(columnSetSignature("mc"), "csc");
793 TEST_F(MultiColumnTreeModifyingTest, RemoveSpannerWithInvalidSpannerBetweenContent)
795 setMulticolHTML("<div id='mc'>text<div id='spanner'><div class='s'></div></div>text</div>");
796 EXPECT_EQ(columnSetSignature("mc"), "csc");
797 destroyLayoutObject("spanner");
798 EXPECT_EQ(columnSetSignature("mc"), "c");
801 } // anonymous namespace
803 } // namespace blink