Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
| 6 | 6 |
| 7 #include "core/dom/NodeComputedStyle.h" | 7 #include "core/dom/NodeComputedStyle.h" |
| 8 #include "core/dom/TagCollection.h" | 8 #include "core/dom/TagCollection.h" |
| 9 #include "core/layout/ng/layout_ng_block_flow.h" | 9 #include "core/layout/ng/layout_ng_block_flow.h" |
| 10 #include "core/layout/ng/ng_block_node.h" | 10 #include "core/layout/ng/ng_block_node.h" |
| 11 #include "core/layout/ng/ng_constraint_space.h" | 11 #include "core/layout/ng/ng_constraint_space.h" |
| 12 #include "core/layout/ng/ng_constraint_space_builder.h" | 12 #include "core/layout/ng/ng_constraint_space_builder.h" |
| 13 #include "core/layout/ng/ng_floating_object.h" | 13 #include "core/layout/ng/ng_floating_object.h" |
| 14 #include "core/layout/ng/ng_length_utils.h" | 14 #include "core/layout/ng/ng_length_utils.h" |
| 15 #include "core/layout/LayoutTestHelper.h" | 15 #include "core/layout/LayoutTestHelper.h" |
| 16 #include "core/layout/ng/ng_physical_box_fragment.h" | 16 #include "core/layout/ng/ng_physical_box_fragment.h" |
| 17 #include "core/layout/ng/ng_physical_fragment.h" | 17 #include "core/layout/ng/ng_physical_fragment.h" |
| 18 #include "core/layout/ng/ng_units.h" | 18 #include "core/layout/ng/ng_units.h" |
| 19 #include "core/style/ComputedStyle.h" | 19 #include "core/style/ComputedStyle.h" |
| 20 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 22 |
| 23 namespace blink { | 23 namespace blink { |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 using testing::ElementsAre; | 26 using testing::ElementsAre; |
| 27 using testing::Pointee; | 27 using testing::Pointee; |
| 28 | 28 |
| 29 NGConstraintSpace* ConstructConstraintSpace(NGWritingMode writing_mode, | 29 NGConstraintSpace* ConstructConstraintSpace( |
| 30 TextDirection direction, | 30 NGWritingMode writing_mode, |
| 31 NGLogicalSize size, | 31 TextDirection direction, |
| 32 bool shrink_to_fit = false) { | 32 NGLogicalSize size, |
| 33 bool shrink_to_fit = false, | |
| 34 LayoutUnit fragmentainer_space_available = LayoutUnit()) { | |
| 35 NGFragmentationType block_fragmentation = | |
| 36 fragmentainer_space_available != LayoutUnit() | |
| 37 ? NGFragmentationType::kFragmentColumn | |
| 38 : NGFragmentationType::kFragmentNone; | |
| 39 | |
| 33 return NGConstraintSpaceBuilder(writing_mode) | 40 return NGConstraintSpaceBuilder(writing_mode) |
| 34 .SetAvailableSize(size) | 41 .SetAvailableSize(size) |
| 35 .SetPercentageResolutionSize(size) | 42 .SetPercentageResolutionSize(size) |
| 36 .SetTextDirection(direction) | 43 .SetTextDirection(direction) |
| 37 .SetIsShrinkToFit(shrink_to_fit) | 44 .SetIsShrinkToFit(shrink_to_fit) |
| 45 .SetFragmentainerSpaceAvailable(fragmentainer_space_available) | |
| 46 .SetFragmentationType(block_fragmentation) | |
| 38 .ToConstraintSpace(writing_mode); | 47 .ToConstraintSpace(writing_mode); |
| 39 } | 48 } |
| 40 | 49 |
| 41 typedef bool TestParamLayoutNG; | 50 typedef bool TestParamLayoutNG; |
| 42 class NGBlockLayoutAlgorithmTest | 51 class NGBlockLayoutAlgorithmTest |
| 43 : public ::testing::WithParamInterface<TestParamLayoutNG>, | 52 : public ::testing::WithParamInterface<TestParamLayoutNG>, |
| 44 public RenderingTest { | 53 public RenderingTest { |
| 45 public: | 54 public: |
| 46 NGBlockLayoutAlgorithmTest() { | 55 NGBlockLayoutAlgorithmTest() { |
| 47 RuntimeEnabledFeatures::setLayoutNGEnabled(true); | 56 RuntimeEnabledFeatures::setLayoutNGEnabled(true); |
| (...skipping 2041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2089 EXPECT_THAT(NGPhysicalOffset(LayoutUnit(8), LayoutUnit(8)), | 2098 EXPECT_THAT(NGPhysicalOffset(LayoutUnit(8), LayoutUnit(8)), |
| 2090 empty_block1->Offset()); | 2099 empty_block1->Offset()); |
| 2091 | 2100 |
| 2092 auto* empty_block2 = | 2101 auto* empty_block2 = |
| 2093 toNGPhysicalBoxFragment(container_fragment->Children()[1].get()); | 2102 toNGPhysicalBoxFragment(container_fragment->Children()[1].get()); |
| 2094 // empty-block2's margin == 50 | 2103 // empty-block2's margin == 50 |
| 2095 EXPECT_THAT(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(50)), | 2104 EXPECT_THAT(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(50)), |
| 2096 empty_block2->Offset()); | 2105 empty_block2->Offset()); |
| 2097 } | 2106 } |
| 2098 | 2107 |
| 2108 // Tests that a block child won't fragment if it doesn't reach the fragmentation | |
| 2109 // line. | |
| 2110 TEST_F(NGBlockLayoutAlgorithmTest, NoFragmentation) { | |
| 2111 setBodyInnerHTML(R"HTML( | |
| 2112 <!DOCTYPE html> | |
| 2113 <style> | |
| 2114 #container { | |
| 2115 width: 150px; | |
| 2116 height: 200px; | |
| 2117 } | |
| 2118 </style> | |
| 2119 <div id='container'></div> | |
| 2120 )HTML"); | |
| 2121 | |
| 2122 LayoutUnit kFragmentainerSpaceAvailable(200); | |
| 2123 | |
| 2124 NGBlockNode* node = new NGBlockNode( | |
| 2125 toLayoutBlockFlow(getLayoutObjectByElementId("container"))); | |
| 2126 auto* space = ConstructConstraintSpace( | |
| 2127 kHorizontalTopBottom, TextDirection::kLtr, | |
| 2128 NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, | |
| 2129 kFragmentainerSpaceAvailable); | |
| 2130 | |
| 2131 // We should only have one 150x200 fragment with no fragmentation. | |
| 2132 RefPtr<const NGPhysicalFragment> fragment = | |
| 2133 NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); | |
| 2134 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(200)), fragment->Size()); | |
| 2135 ASSERT_TRUE(fragment->BreakToken()->IsFinished()); | |
| 2136 } | |
| 2137 | |
| 2138 // Tests that a block child with fragment if it reaches the fragmentation line. | |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
I don't think I can parse this sentence, but I thi
ikilpatrick
2017/02/27 18:50:09
s/with/will :P
| |
| 2139 TEST_F(NGBlockLayoutAlgorithmTest, SimpleFragmentation) { | |
| 2140 setBodyInnerHTML(R"HTML( | |
| 2141 <!DOCTYPE html> | |
| 2142 <style> | |
| 2143 #container { | |
| 2144 width: 150px; | |
| 2145 height: 300px; | |
| 2146 } | |
| 2147 </style> | |
| 2148 <div id='container'></div> | |
| 2149 )HTML"); | |
| 2150 | |
| 2151 LayoutUnit kFragmentainerSpaceAvailable(200); | |
| 2152 | |
| 2153 NGBlockNode* node = new NGBlockNode( | |
| 2154 toLayoutBlockFlow(getLayoutObjectByElementId("container"))); | |
| 2155 auto* space = ConstructConstraintSpace( | |
| 2156 kHorizontalTopBottom, TextDirection::kLtr, | |
| 2157 NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, | |
| 2158 kFragmentainerSpaceAvailable); | |
| 2159 | |
| 2160 RefPtr<const NGPhysicalFragment> fragment = | |
| 2161 NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); | |
| 2162 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(200)), fragment->Size()); | |
| 2163 ASSERT_FALSE(fragment->BreakToken()->IsFinished()); | |
| 2164 | |
| 2165 fragment = NGBlockLayoutAlgorithm(node, space, | |
| 2166 toNGBlockBreakToken(fragment->BreakToken())) | |
| 2167 .Layout() | |
| 2168 ->PhysicalFragment(); | |
| 2169 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(100)), fragment->Size()); | |
| 2170 ASSERT_TRUE(fragment->BreakToken()->IsFinished()); | |
| 2171 } | |
| 2172 | |
| 2173 // Tests that children inside the same block formatting context fragment when | |
| 2174 // reaching a fragmentation line. | |
| 2175 TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentation) { | |
| 2176 setBodyInnerHTML(R"HTML( | |
| 2177 <!DOCTYPE html> | |
| 2178 <style> | |
| 2179 #container { | |
| 2180 width: 150px; | |
| 2181 padding-top: 20px; | |
| 2182 } | |
| 2183 #child1 { | |
| 2184 height: 200px; | |
| 2185 margin-bottom: 20px; | |
| 2186 } | |
| 2187 #child2 { | |
| 2188 height: 100px; | |
| 2189 margin-top: 20px; | |
| 2190 } | |
| 2191 </style> | |
| 2192 <div id='container'> | |
| 2193 <div id='child1'></div> | |
| 2194 <div id='child2'></div> | |
| 2195 </div> | |
| 2196 )HTML"); | |
| 2197 | |
| 2198 LayoutUnit kFragmentainerSpaceAvailable(200); | |
| 2199 | |
| 2200 NGBlockNode* node = new NGBlockNode( | |
| 2201 toLayoutBlockFlow(getLayoutObjectByElementId("container"))); | |
| 2202 auto* space = ConstructConstraintSpace( | |
| 2203 kHorizontalTopBottom, TextDirection::kLtr, | |
| 2204 NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, | |
| 2205 kFragmentainerSpaceAvailable); | |
| 2206 | |
| 2207 RefPtr<const NGPhysicalFragment> fragment = | |
| 2208 NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); | |
| 2209 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(200)), fragment->Size()); | |
| 2210 ASSERT_FALSE(fragment->BreakToken()->IsFinished()); | |
| 2211 | |
| 2212 FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); | |
| 2213 const NGPhysicalBoxFragment* child = iterator.NextChild(); | |
| 2214 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(180)), child->Size()); | |
| 2215 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(20)), child->Offset()); | |
| 2216 | |
| 2217 EXPECT_FALSE(iterator.NextChild()); | |
| 2218 | |
| 2219 fragment = NGBlockLayoutAlgorithm(node, space, | |
| 2220 toNGBlockBreakToken(fragment->BreakToken())) | |
| 2221 .Layout() | |
| 2222 ->PhysicalFragment(); | |
| 2223 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(140)), fragment->Size()); | |
| 2224 ASSERT_TRUE(fragment->BreakToken()->IsFinished()); | |
| 2225 | |
| 2226 iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); | |
| 2227 child = iterator.NextChild(); | |
| 2228 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(20)), child->Size()); | |
| 2229 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset()); | |
| 2230 | |
| 2231 child = iterator.NextChild(); | |
| 2232 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(100)), child->Size()); | |
| 2233 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(40)), child->Offset()); | |
| 2234 | |
| 2235 EXPECT_FALSE(iterator.NextChild()); | |
| 2236 } | |
| 2237 | |
| 2238 // Tests that children inside which establish new formatting contexts fragment | |
| 2239 // correctly. | |
| 2240 TEST_F(NGBlockLayoutAlgorithmTest, | |
| 2241 InnerFormattingContextChildrenFragmentation) { | |
| 2242 setBodyInnerHTML(R"HTML( | |
| 2243 <!DOCTYPE html> | |
| 2244 <style> | |
| 2245 #container { | |
| 2246 width: 150px; | |
| 2247 padding-top: 20px; | |
| 2248 } | |
| 2249 #child1 { | |
| 2250 height: 200px; | |
| 2251 margin-bottom: 20px; | |
| 2252 contain: paint; | |
| 2253 } | |
| 2254 #child2 { | |
| 2255 height: 100px; | |
| 2256 margin-top: 20px; | |
| 2257 contain: paint; | |
| 2258 } | |
| 2259 </style> | |
| 2260 <div id='container'> | |
| 2261 <div id='child1'></div> | |
| 2262 <div id='child2'></div> | |
| 2263 </div> | |
| 2264 )HTML"); | |
| 2265 | |
| 2266 LayoutUnit kFragmentainerSpaceAvailable(200); | |
| 2267 | |
| 2268 NGBlockNode* node = new NGBlockNode( | |
| 2269 toLayoutBlockFlow(getLayoutObjectByElementId("container"))); | |
| 2270 auto* space = ConstructConstraintSpace( | |
| 2271 kHorizontalTopBottom, TextDirection::kLtr, | |
| 2272 NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, | |
| 2273 kFragmentainerSpaceAvailable); | |
| 2274 | |
| 2275 RefPtr<const NGPhysicalFragment> fragment = | |
| 2276 NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); | |
| 2277 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(200)), fragment->Size()); | |
| 2278 ASSERT_FALSE(fragment->BreakToken()->IsFinished()); | |
| 2279 | |
| 2280 FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); | |
| 2281 const NGPhysicalBoxFragment* child = iterator.NextChild(); | |
| 2282 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(180)), child->Size()); | |
| 2283 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(20)), child->Offset()); | |
| 2284 | |
| 2285 EXPECT_FALSE(iterator.NextChild()); | |
| 2286 | |
| 2287 fragment = NGBlockLayoutAlgorithm(node, space, | |
| 2288 toNGBlockBreakToken(fragment->BreakToken())) | |
| 2289 .Layout() | |
| 2290 ->PhysicalFragment(); | |
| 2291 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(140)), fragment->Size()); | |
| 2292 ASSERT_TRUE(fragment->BreakToken()->IsFinished()); | |
| 2293 | |
| 2294 iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); | |
| 2295 child = iterator.NextChild(); | |
| 2296 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(20)), child->Size()); | |
| 2297 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset()); | |
| 2298 | |
| 2299 child = iterator.NextChild(); | |
| 2300 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(100)), child->Size()); | |
| 2301 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(40)), child->Offset()); | |
| 2302 | |
| 2303 EXPECT_FALSE(iterator.NextChild()); | |
| 2304 } | |
| 2305 | |
| 2306 // Tests that children inside which establish new formatting contexts fragment | |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
Comment is the same as the one before the previous
ikilpatrick
2017/02/27 18:50:09
Done.
| |
| 2307 // correctly. | |
| 2308 TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentationSmallHeight) { | |
| 2309 setBodyInnerHTML(R"HTML( | |
| 2310 <!DOCTYPE html> | |
| 2311 <style> | |
| 2312 #container { | |
| 2313 width: 150px; | |
| 2314 padding-top: 20px; | |
| 2315 height: 50px; | |
| 2316 } | |
| 2317 #child1 { | |
| 2318 height: 200px; | |
| 2319 margin-bottom: 20px; | |
| 2320 } | |
| 2321 #child2 { | |
| 2322 height: 100px; | |
| 2323 margin-top: 20px; | |
| 2324 } | |
| 2325 </style> | |
| 2326 <div id='container'> | |
| 2327 <div id='child1'></div> | |
| 2328 <div id='child2'></div> | |
| 2329 </div> | |
| 2330 )HTML"); | |
| 2331 | |
| 2332 LayoutUnit kFragmentainerSpaceAvailable(200); | |
| 2333 | |
| 2334 NGBlockNode* node = new NGBlockNode( | |
| 2335 toLayoutBlockFlow(getLayoutObjectByElementId("container"))); | |
| 2336 auto* space = ConstructConstraintSpace( | |
| 2337 kHorizontalTopBottom, TextDirection::kLtr, | |
| 2338 NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, | |
| 2339 kFragmentainerSpaceAvailable); | |
| 2340 | |
| 2341 RefPtr<const NGPhysicalFragment> fragment = | |
| 2342 NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); | |
| 2343 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(70)), fragment->Size()); | |
| 2344 ASSERT_FALSE(fragment->BreakToken()->IsFinished()); | |
| 2345 | |
| 2346 FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); | |
| 2347 const NGPhysicalBoxFragment* child = iterator.NextChild(); | |
| 2348 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(180)), child->Size()); | |
| 2349 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(20)), child->Offset()); | |
| 2350 | |
| 2351 EXPECT_FALSE(iterator.NextChild()); | |
| 2352 | |
| 2353 fragment = NGBlockLayoutAlgorithm(node, space, | |
| 2354 toNGBlockBreakToken(fragment->BreakToken())) | |
| 2355 .Layout() | |
| 2356 ->PhysicalFragment(); | |
| 2357 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(0)), fragment->Size()); | |
| 2358 ASSERT_TRUE(fragment->BreakToken()->IsFinished()); | |
| 2359 | |
| 2360 iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); | |
| 2361 child = iterator.NextChild(); | |
| 2362 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(20)), child->Size()); | |
| 2363 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset()); | |
| 2364 | |
| 2365 child = iterator.NextChild(); | |
| 2366 EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(100)), child->Size()); | |
| 2367 EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(40)), child->Offset()); | |
| 2368 | |
| 2369 EXPECT_FALSE(iterator.NextChild()); | |
| 2370 } | |
| 2371 | |
| 2099 } // namespace | 2372 } // namespace |
| 2100 } // namespace blink | 2373 } // namespace blink |
| OLD | NEW |