OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "config.h" |
| 6 |
| 7 #include "core/rendering/RenderMultiColumnFlowThread.h" |
| 8 |
| 9 #include "core/rendering/RenderMultiColumnSet.h" |
| 10 #include "core/rendering/RenderMultiColumnSpannerSet.h" |
| 11 #include "core/rendering/RenderingTestHelper.h" |
| 12 |
| 13 #include <gtest/gtest.h> |
| 14 |
| 15 namespace blink { |
| 16 |
| 17 namespace { |
| 18 |
| 19 class MultiColumnRenderingTest : public RenderingTest { |
| 20 public: |
| 21 RenderMultiColumnFlowThread* findFlowThread(const char* id) const; |
| 22 |
| 23 // Generate a signature string based on what kind of column sets the flow th
read has |
| 24 // established. There will be one character for each column set. 'c' is used
for regular column |
| 25 // content sets, while 's' is used for spanner sets. |
| 26 String columnSetSignature(RenderMultiColumnFlowThread*); |
| 27 String columnSetSignature(const char* multicolId); |
| 28 |
| 29 void setMulticolHTML(const String&); |
| 30 }; |
| 31 |
| 32 RenderMultiColumnFlowThread* MultiColumnRenderingTest::findFlowThread(const char
* id) const |
| 33 { |
| 34 Node* multicol = document().getElementById(id); |
| 35 if (!multicol) |
| 36 return 0; |
| 37 RenderBlockFlow* multicolContainer = toRenderBlockFlow(multicol->renderer())
; |
| 38 if (!multicolContainer) |
| 39 return 0; |
| 40 return multicolContainer->multiColumnFlowThread(); |
| 41 } |
| 42 |
| 43 String MultiColumnRenderingTest::columnSetSignature(RenderMultiColumnFlowThread*
flowThread) |
| 44 { |
| 45 String signature = ""; |
| 46 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); co
lumnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { |
| 47 if (columnSet->isRenderMultiColumnSpannerSet()) |
| 48 signature.append('s'); |
| 49 else |
| 50 signature.append('c'); |
| 51 } |
| 52 return signature; |
| 53 } |
| 54 |
| 55 String MultiColumnRenderingTest::columnSetSignature(const char* multicolId) |
| 56 { |
| 57 return columnSetSignature(findFlowThread(multicolId)); |
| 58 } |
| 59 |
| 60 void MultiColumnRenderingTest::setMulticolHTML(const String& html) |
| 61 { |
| 62 const char* style = |
| 63 "<style>" |
| 64 " #mc { -webkit-columns:2; }" |
| 65 " .s, #spanner, #spanner1, #spanner2 { -webkit-column-span:all; }" |
| 66 "</style>"; |
| 67 setBodyInnerHTML(style + html); |
| 68 } |
| 69 |
| 70 TEST_F(MultiColumnRenderingTest, OneBlockWithInDepthTreeStructureCheck) |
| 71 { |
| 72 // Examine the render tree established by a simple multicol container with a
block with some text inside. |
| 73 setMulticolHTML("<div id='mc'><div>xxx</div></div>"); |
| 74 Node* multicol = document().getElementById("mc"); |
| 75 ASSERT_TRUE(multicol); |
| 76 RenderBlockFlow* multicolContainer = toRenderBlockFlow(multicol->renderer())
; |
| 77 ASSERT_TRUE(multicolContainer); |
| 78 RenderMultiColumnFlowThread* flowThread = multicolContainer->multiColumnFlow
Thread(); |
| 79 ASSERT_TRUE(flowThread); |
| 80 EXPECT_EQ(columnSetSignature(flowThread), "c"); |
| 81 EXPECT_EQ(flowThread->parent(), multicolContainer); |
| 82 EXPECT_FALSE(flowThread->previousSibling()); |
| 83 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 84 ASSERT_TRUE(columnSet); |
| 85 EXPECT_EQ(columnSet->previousSibling(), flowThread); |
| 86 EXPECT_FALSE(columnSet->nextSibling()); |
| 87 RenderBlockFlow* block = toRenderBlockFlow(flowThread->firstChild()); |
| 88 ASSERT_TRUE(block); |
| 89 EXPECT_FALSE(block->nextSibling()); |
| 90 ASSERT_TRUE(block->firstChild()); |
| 91 EXPECT_TRUE(block->firstChild()->isText()); |
| 92 EXPECT_FALSE(block->firstChild()->nextSibling()); |
| 93 } |
| 94 |
| 95 TEST_F(MultiColumnRenderingTest, Empty) |
| 96 { |
| 97 // If there's no column content, there should be no column set. |
| 98 setMulticolHTML("<div id='mc'></div>"); |
| 99 EXPECT_EQ(columnSetSignature("mc"), ""); |
| 100 } |
| 101 |
| 102 TEST_F(MultiColumnRenderingTest, OneBlock) |
| 103 { |
| 104 // There is some content, so we should create a column set. |
| 105 setMulticolHTML("<div id='mc'><div id='block'></div></div>"); |
| 106 ASSERT_EQ(columnSetSignature("mc"), "c"); |
| 107 } |
| 108 |
| 109 TEST_F(MultiColumnRenderingTest, TwoBlocks) |
| 110 { |
| 111 // No matter how much content, we should only create one column set (unless
there are spanners). |
| 112 setMulticolHTML("<div id='mc'><div id='block1'></div><div id='block2'></div>
</div>"); |
| 113 ASSERT_EQ(columnSetSignature("mc"), "c"); |
| 114 } |
| 115 |
| 116 TEST_F(MultiColumnRenderingTest, Spanner) |
| 117 { |
| 118 // With one spanner and no column content, we should create a spanner set. |
| 119 setMulticolHTML("<div id='mc'><div id='spanner'></div></div>"); |
| 120 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 121 ASSERT_EQ(columnSetSignature(flowThread), "s"); |
| 122 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 123 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 124 } |
| 125 |
| 126 TEST_F(MultiColumnRenderingTest, ContentThenSpanner) |
| 127 { |
| 128 // With some column content followed by a spanner, we need a column set foll
owed by a spanner set. |
| 129 setMulticolHTML("<div id='mc'><div id='columnContent'></div><div id='spanner
'></div></div>"); |
| 130 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 131 ASSERT_EQ(columnSetSignature(flowThread), "cs"); |
| 132 RenderMultiColumnSet* columnSet = flowThread->lastMultiColumnSet(); |
| 133 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 134 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
columnContent")->renderer()), nullptr); |
| 135 } |
| 136 |
| 137 TEST_F(MultiColumnRenderingTest, SpannerThenContent) |
| 138 { |
| 139 // With a spanner followed by some column content, we need a spanner set fol
lowed by a column set. |
| 140 setMulticolHTML("<div id='mc'><div id='spanner'></div><div id='columnContent
'></div></div>"); |
| 141 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 142 ASSERT_EQ(columnSetSignature(flowThread), "sc"); |
| 143 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 144 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 145 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
columnContent")->renderer()), nullptr); |
| 146 } |
| 147 |
| 148 TEST_F(MultiColumnRenderingTest, ContentThenSpannerThenContent) |
| 149 { |
| 150 // With column content followed by a spanner followed by some column content
, we need a column |
| 151 // set followed by a spanner set followed by a column set. |
| 152 setMulticolHTML("<div id='mc'><div id='columnContentBefore'></div><div id='s
panner'></div><div id='columnContentAfter'></div></div>"); |
| 153 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 154 ASSERT_EQ(columnSetSignature(flowThread), "csc"); |
| 155 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet()->nextSib
lingMultiColumnSet(); |
| 156 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
columnContentBefore")->renderer()), nullptr); |
| 157 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 158 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
columnContentAfter")->renderer()), nullptr); |
| 159 } |
| 160 |
| 161 TEST_F(MultiColumnRenderingTest, TwoSpanners) |
| 162 { |
| 163 // With two spanners and no column content, we need two spanner sets. |
| 164 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='spanner2'></
div></div>"); |
| 165 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 166 ASSERT_EQ(columnSetSignature(flowThread), "ss"); |
| 167 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 168 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner1")->renderer()), columnSet); |
| 169 columnSet = columnSet->nextSiblingMultiColumnSet(); |
| 170 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner2")->renderer()), columnSet); |
| 171 } |
| 172 |
| 173 TEST_F(MultiColumnRenderingTest, SpannerThenContentThenSpanner) |
| 174 { |
| 175 // With two spanners and some column content in-between, we need a spanner s
et, a column set and another spanner set. |
| 176 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='columnConten
t'></div><div id='spanner2'></div></div>"); |
| 177 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 178 ASSERT_EQ(columnSetSignature(flowThread), "scs"); |
| 179 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 180 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner1")->renderer()), columnSet); |
| 181 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
columnContent")->renderer()), nullptr); |
| 182 columnSet = columnSet->nextSiblingMultiColumnSet()->nextSiblingMultiColumnSe
t(); |
| 183 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner2")->renderer()), columnSet); |
| 184 } |
| 185 |
| 186 TEST_F(MultiColumnRenderingTest, SpannerWithSpanner) |
| 187 { |
| 188 // column-span:all on something inside column-span:all has no effect. |
| 189 setMulticolHTML("<div id='mc'><div id='spanner'><div id='invalidSpanner' cla
ss='s'></div></div></div>"); |
| 190 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 191 ASSERT_EQ(columnSetSignature(flowThread), "s"); |
| 192 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 193 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 194 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
invalidSpanner")->renderer()), columnSet); |
| 195 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner")->renderer()); |
| 196 } |
| 197 |
| 198 TEST_F(MultiColumnRenderingTest, SubtreeWithSpanner) |
| 199 { |
| 200 setMulticolHTML("<div id='mc'><div id='outer'><div id='block1'></div><div id
='spanner'></div><div id='block2'></div></div></div>"); |
| 201 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 202 EXPECT_EQ(columnSetSignature(flowThread), "csc"); |
| 203 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet()->nextSib
lingMultiColumnSet(); |
| 204 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner")->renderer()), columnSet); |
| 205 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner")->renderer()); |
| 206 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
outer")->renderer()), nullptr); |
| 207 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
block1")->renderer()), nullptr); |
| 208 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
block2")->renderer()), nullptr); |
| 209 } |
| 210 |
| 211 TEST_F(MultiColumnRenderingTest, SubtreeWithSpannerAfterSpanner) |
| 212 { |
| 213 setMulticolHTML("<div id='mc'><div id='spanner1'></div><div id='outer'>text<
div id='spanner2'></div><div id='after'></div></div></div>"); |
| 214 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 215 EXPECT_EQ(columnSetSignature(flowThread), "scsc"); |
| 216 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); |
| 217 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner1")->renderer()), columnSet); |
| 218 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner1")->renderer()); |
| 219 columnSet = columnSet->nextSiblingMultiColumnSet()->nextSiblingMultiColumnSe
t(); |
| 220 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner2")->renderer()), columnSet); |
| 221 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner2")->renderer()); |
| 222 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
outer")->renderer()), nullptr); |
| 223 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
after")->renderer()), nullptr); |
| 224 } |
| 225 |
| 226 TEST_F(MultiColumnRenderingTest, SubtreeWithSpannerBeforeSpanner) |
| 227 { |
| 228 setMulticolHTML("<div id='mc'><div id='outer'>text<div id='spanner1'></div>t
ext</div><div id='spanner2'></div></div>"); |
| 229 RenderMultiColumnFlowThread* flowThread = findFlowThread("mc"); |
| 230 EXPECT_EQ(columnSetSignature(flowThread), "cscs"); |
| 231 RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet()->nextSib
lingMultiColumnSet(); |
| 232 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner1")->renderer()), columnSet); |
| 233 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner1")->renderer()); |
| 234 columnSet = columnSet->nextSiblingMultiColumnSet()->nextSiblingMultiColumnSe
t(); |
| 235 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
spanner2")->renderer()), columnSet); |
| 236 EXPECT_EQ(toRenderMultiColumnSpannerSet(columnSet)->rendererInFlowThread(),
document().getElementById("spanner2")->renderer()); |
| 237 EXPECT_EQ(flowThread->containingColumnSpannerSet(document().getElementById("
outer")->renderer()), nullptr); |
| 238 } |
| 239 |
| 240 } // anonymous namespace |
| 241 |
| 242 } // namespace blink |
OLD | NEW |