OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Apple Inc. All rights reserved. | 2 * Copyright (C) 2012 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 } | 71 } |
72 return nullptr; | 72 return nullptr; |
73 } | 73 } |
74 | 74 |
75 static inline bool isMultiColumnContainer(const LayoutObject& object) { | 75 static inline bool isMultiColumnContainer(const LayoutObject& object) { |
76 if (!object.isLayoutBlockFlow()) | 76 if (!object.isLayoutBlockFlow()) |
77 return false; | 77 return false; |
78 return toLayoutBlockFlow(object).multiColumnFlowThread(); | 78 return toLayoutBlockFlow(object).multiColumnFlowThread(); |
79 } | 79 } |
80 | 80 |
81 // Return true if there's nothing that prevents the specified object from being
in the ancestor | 81 // Return true if there's nothing that prevents the specified object from being |
82 // chain between some column spanner and its containing multicol container. A co
lumn spanner needs | 82 // in the ancestor chain between some column spanner and its containing multicol |
83 // the multicol container to be its containing block, so that the spanner is abl
e to escape the flow | 83 // container. A column spanner needs the multicol container to be its containing |
84 // thread. (Everything contained by the flow thread is split into columns, but t
his is precisely | 84 // block, so that the spanner is able to escape the flow thread. (Everything |
85 // what shouldn't be done to a spanner, since it's supposed to span all columns.
) | 85 // contained by the flow thread is split into columns, but this is precisely |
| 86 // what shouldn't be done to a spanner, since it's supposed to span all |
| 87 // columns.) |
86 // | 88 // |
87 // We require that the parent of the spanner participate in the block formatting
context established | 89 // We require that the parent of the spanner participate in the block formatting |
88 // by the multicol container (i.e. that there are no BFCs or other formatting co
ntexts | 90 // context established by the multicol container (i.e. that there are no BFCs or |
89 // in-between). We also require that there be no transforms, since transforms in
sist on being in the | 91 // other formatting contexts in-between). We also require that there be no |
90 // containing block chain for everything inside it, which conflicts with a spann
ers's need to have | 92 // transforms, since transforms insist on being in the containing block chain |
91 // the multicol container as its direct containing block. We may also not put sp
anners inside | 93 // for everything inside it, which conflicts with a spanners's need to have the |
92 // objects that don't support fragmentation. | 94 // multicol container as its direct containing block. We may also not put |
| 95 // spanners inside objects that don't support fragmentation. |
93 static inline bool canContainSpannerInParentFragmentationContext( | 96 static inline bool canContainSpannerInParentFragmentationContext( |
94 const LayoutObject& object) { | 97 const LayoutObject& object) { |
95 if (!object.isLayoutBlockFlow()) | 98 if (!object.isLayoutBlockFlow()) |
96 return false; | 99 return false; |
97 const LayoutBlockFlow& blockFlow = toLayoutBlockFlow(object); | 100 const LayoutBlockFlow& blockFlow = toLayoutBlockFlow(object); |
98 return !blockFlow.createsNewFormattingContext() && | 101 return !blockFlow.createsNewFormattingContext() && |
99 !blockFlow.hasTransformRelatedProperty() && | 102 !blockFlow.hasTransformRelatedProperty() && |
100 blockFlow.getPaginationBreakability() != LayoutBox::ForbidBreaks && | 103 blockFlow.getPaginationBreakability() != LayoutBox::ForbidBreaks && |
101 !isMultiColumnContainer(blockFlow); | 104 !isMultiColumnContainer(blockFlow); |
102 } | 105 } |
103 | 106 |
104 static inline bool hasAnyColumnSpanners( | 107 static inline bool hasAnyColumnSpanners( |
105 const LayoutMultiColumnFlowThread& flowThread) { | 108 const LayoutMultiColumnFlowThread& flowThread) { |
106 LayoutBox* firstBox = flowThread.firstMultiColumnBox(); | 109 LayoutBox* firstBox = flowThread.firstMultiColumnBox(); |
107 return firstBox && (firstBox != flowThread.lastMultiColumnBox() || | 110 return firstBox && (firstBox != flowThread.lastMultiColumnBox() || |
108 firstBox->isLayoutMultiColumnSpannerPlaceholder()); | 111 firstBox->isLayoutMultiColumnSpannerPlaceholder()); |
109 } | 112 } |
110 | 113 |
111 // Find the next layout object that has the multicol container in its containing
block chain, skipping nested multicol containers. | 114 // Find the next layout object that has the multicol container in its containing |
| 115 // block chain, skipping nested multicol containers. |
112 static LayoutObject* nextInPreOrderAfterChildrenSkippingOutOfFlow( | 116 static LayoutObject* nextInPreOrderAfterChildrenSkippingOutOfFlow( |
113 LayoutMultiColumnFlowThread* flowThread, | 117 LayoutMultiColumnFlowThread* flowThread, |
114 LayoutObject* descendant) { | 118 LayoutObject* descendant) { |
115 ASSERT(descendant->isDescendantOf(flowThread)); | 119 ASSERT(descendant->isDescendantOf(flowThread)); |
116 LayoutObject* object = descendant->nextInPreOrderAfterChildren(flowThread); | 120 LayoutObject* object = descendant->nextInPreOrderAfterChildren(flowThread); |
117 while (object) { | 121 while (object) { |
118 // Walk through the siblings and find the first one which is either in-flow
or has this | 122 // Walk through the siblings and find the first one which is either in-flow |
119 // flow thread as its containing block flow thread. | 123 // or has this flow thread as its containing block flow thread. |
120 if (!object->isOutOfFlowPositioned()) | 124 if (!object->isOutOfFlowPositioned()) |
121 break; | 125 break; |
122 if (object->containingBlock()->flowThreadContainingBlock() == flowThread) { | 126 if (object->containingBlock()->flowThreadContainingBlock() == flowThread) { |
123 // This out-of-flow object is still part of the flow thread, because its c
ontaining | 127 // This out-of-flow object is still part of the flow thread, because its |
124 // block (probably relatively positioned) is part of the flow thread. | 128 // containing block (probably relatively positioned) is part of the flow |
| 129 // thread. |
125 break; | 130 break; |
126 } | 131 } |
127 object = object->nextInPreOrderAfterChildren(flowThread); | 132 object = object->nextInPreOrderAfterChildren(flowThread); |
128 } | 133 } |
129 if (!object) | 134 if (!object) |
130 return nullptr; | 135 return nullptr; |
131 #if ENABLE(ASSERT) | 136 #if ENABLE(ASSERT) |
132 // Make sure that we didn't stumble into an inner multicol container. | 137 // Make sure that we didn't stumble into an inner multicol container. |
133 for (LayoutObject* walker = object->parent(); walker && walker != flowThread; | 138 for (LayoutObject* walker = object->parent(); walker && walker != flowThread; |
134 walker = walker->parent()) | 139 walker = walker->parent()) |
135 ASSERT(!isMultiColumnContainer(*walker)); | 140 ASSERT(!isMultiColumnContainer(*walker)); |
136 #endif | 141 #endif |
137 return object; | 142 return object; |
138 } | 143 } |
139 | 144 |
140 // Find the previous layout object that has the multicol container in its contai
ning block chain, skipping nested multicol containers. | 145 // Find the previous layout object that has the multicol container in its |
| 146 // containing block chain, skipping nested multicol containers. |
141 static LayoutObject* previousInPreOrderSkippingOutOfFlow( | 147 static LayoutObject* previousInPreOrderSkippingOutOfFlow( |
142 LayoutMultiColumnFlowThread* flowThread, | 148 LayoutMultiColumnFlowThread* flowThread, |
143 LayoutObject* descendant) { | 149 LayoutObject* descendant) { |
144 ASSERT(descendant->isDescendantOf(flowThread)); | 150 ASSERT(descendant->isDescendantOf(flowThread)); |
145 LayoutObject* object = descendant->previousInPreOrder(flowThread); | 151 LayoutObject* object = descendant->previousInPreOrder(flowThread); |
146 while (object && object != flowThread) { | 152 while (object && object != flowThread) { |
147 if (object->isColumnSpanAll()) { | 153 if (object->isColumnSpanAll()) { |
148 LayoutMultiColumnFlowThread* placeholderFlowThread = | 154 LayoutMultiColumnFlowThread* placeholderFlowThread = |
149 toLayoutBox(object)->spannerPlaceholder()->flowThread(); | 155 toLayoutBox(object)->spannerPlaceholder()->flowThread(); |
150 if (placeholderFlowThread == flowThread) | 156 if (placeholderFlowThread == flowThread) |
151 break; | 157 break; |
152 // We're inside an inner multicol container. We have no business there. Co
ntinue on the outside. | 158 // We're inside an inner multicol container. We have no business there. |
| 159 // Continue on the outside. |
153 object = placeholderFlowThread->parent(); | 160 object = placeholderFlowThread->parent(); |
154 ASSERT(object->isDescendantOf(flowThread)); | 161 ASSERT(object->isDescendantOf(flowThread)); |
155 continue; | 162 continue; |
156 } | 163 } |
157 if (object->flowThreadContainingBlock() == flowThread) { | 164 if (object->flowThreadContainingBlock() == flowThread) { |
158 LayoutObject* ancestor; | 165 LayoutObject* ancestor; |
159 for (ancestor = object->parent();; ancestor = ancestor->parent()) { | 166 for (ancestor = object->parent();; ancestor = ancestor->parent()) { |
160 if (ancestor == flowThread) | 167 if (ancestor == flowThread) |
161 return object; | 168 return object; |
162 if (isMultiColumnContainer(*ancestor)) { | 169 if (isMultiColumnContainer(*ancestor)) { |
163 // We're inside an inner multicol container. We have no business there
. | 170 // We're inside an inner multicol container. We have no business |
| 171 // there. |
164 break; | 172 break; |
165 } | 173 } |
166 } | 174 } |
167 object = ancestor; | 175 object = ancestor; |
168 ASSERT(ancestor->isDescendantOf(flowThread)); | 176 ASSERT(ancestor->isDescendantOf(flowThread)); |
169 continue; // Continue on the outside of the inner flow thread. | 177 continue; // Continue on the outside of the inner flow thread. |
170 } | 178 } |
171 // We're inside something that's out-of-flow. Keep looking upwards and backw
ards in the tree. | 179 // We're inside something that's out-of-flow. Keep looking upwards and |
| 180 // backwards in the tree. |
172 object = object->previousInPreOrder(flowThread); | 181 object = object->previousInPreOrder(flowThread); |
173 } | 182 } |
174 if (!object || object == flowThread) | 183 if (!object || object == flowThread) |
175 return nullptr; | 184 return nullptr; |
176 #if ENABLE(ASSERT) | 185 #if ENABLE(ASSERT) |
177 // Make sure that we didn't stumble into an inner multicol container. | 186 // Make sure that we didn't stumble into an inner multicol container. |
178 for (LayoutObject* walker = object->parent(); walker && walker != flowThread; | 187 for (LayoutObject* walker = object->parent(); walker && walker != flowThread; |
179 walker = walker->parent()) | 188 walker = walker->parent()) |
180 ASSERT(!isMultiColumnContainer(*walker)); | 189 ASSERT(!isMultiColumnContainer(*walker)); |
181 #endif | 190 #endif |
182 return object; | 191 return object; |
183 } | 192 } |
184 | 193 |
185 static LayoutObject* firstLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { | 194 static LayoutObject* firstLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { |
186 LayoutBox* sibling = multicolSet->previousSiblingMultiColumnBox(); | 195 LayoutBox* sibling = multicolSet->previousSiblingMultiColumnBox(); |
187 if (!sibling) | 196 if (!sibling) |
188 return multicolSet->flowThread()->firstChild(); | 197 return multicolSet->flowThread()->firstChild(); |
189 // Adjacent column content sets should not occur. We would have no way of figu
ring out what each | 198 // Adjacent column content sets should not occur. We would have no way of |
190 // of them contains then. | 199 // figuring out what each of them contains then. |
191 ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); | 200 ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); |
192 LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling) | 201 LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling) |
193 ->layoutObjectInFlowThread(); | 202 ->layoutObjectInFlowThread(); |
194 return nextInPreOrderAfterChildrenSkippingOutOfFlow( | 203 return nextInPreOrderAfterChildrenSkippingOutOfFlow( |
195 multicolSet->multiColumnFlowThread(), spanner); | 204 multicolSet->multiColumnFlowThread(), spanner); |
196 } | 205 } |
197 | 206 |
198 static LayoutObject* lastLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { | 207 static LayoutObject* lastLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { |
199 LayoutBox* sibling = multicolSet->nextSiblingMultiColumnBox(); | 208 LayoutBox* sibling = multicolSet->nextSiblingMultiColumnBox(); |
| 209 // By right we should return lastLeafChild() here, but the caller doesn't |
| 210 // care, so just return nullptr. |
200 if (!sibling) | 211 if (!sibling) |
201 return nullptr; // By right we should return lastLeafChild() here, but the
caller doesn't care, so just return 0. | 212 return nullptr; |
202 // Adjacent column content sets should not occur. We would have no way of figu
ring out what each | 213 // Adjacent column content sets should not occur. We would have no way of |
203 // of them contains then. | 214 // figuring out what each of them contains then. |
204 ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); | 215 ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); |
205 LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling) | 216 LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling) |
206 ->layoutObjectInFlowThread(); | 217 ->layoutObjectInFlowThread(); |
207 return previousInPreOrderSkippingOutOfFlow( | 218 return previousInPreOrderSkippingOutOfFlow( |
208 multicolSet->multiColumnFlowThread(), spanner); | 219 multicolSet->multiColumnFlowThread(), spanner); |
209 } | 220 } |
210 | 221 |
211 LayoutMultiColumnSet* LayoutMultiColumnFlowThread::mapDescendantToColumnSet( | 222 LayoutMultiColumnSet* LayoutMultiColumnFlowThread::mapDescendantToColumnSet( |
212 LayoutObject* layoutObject) const { | 223 LayoutObject* layoutObject) const { |
213 ASSERT(!containingColumnSpannerPlaceholder( | 224 // Should not be used for spanners or content inside them. |
214 layoutObject)); // should not be used for spanners or content inside them
. | 225 DCHECK(!containingColumnSpannerPlaceholder(layoutObject)); |
215 ASSERT(layoutObject != this); | 226 DCHECK(layoutObject != this); |
216 ASSERT(layoutObject->isDescendantOf(this)); | 227 DCHECK(layoutObject->isDescendantOf(this)); |
217 ASSERT(layoutObject->containingBlock()->isDescendantOf( | 228 // Out-of-flow objects don't belong in column sets. |
218 this)); // Out-of-flow objects don't belong in column sets. | 229 DCHECK(layoutObject->containingBlock()->isDescendantOf(this)); |
219 ASSERT(layoutObject->flowThreadContainingBlock() == this); | 230 DCHECK(layoutObject->flowThreadContainingBlock() == this); |
220 ASSERT(!layoutObject->isLayoutMultiColumnSet()); | 231 DCHECK(!layoutObject->isLayoutMultiColumnSet()); |
221 ASSERT(!layoutObject->isLayoutMultiColumnSpannerPlaceholder()); | 232 DCHECK(!layoutObject->isLayoutMultiColumnSpannerPlaceholder()); |
222 LayoutMultiColumnSet* multicolSet = firstMultiColumnSet(); | 233 LayoutMultiColumnSet* multicolSet = firstMultiColumnSet(); |
223 if (!multicolSet) | 234 if (!multicolSet) |
224 return nullptr; | 235 return nullptr; |
225 if (!multicolSet->nextSiblingMultiColumnSet()) | 236 if (!multicolSet->nextSiblingMultiColumnSet()) |
226 return multicolSet; | 237 return multicolSet; |
227 | 238 |
228 // This is potentially SLOW! But luckily very uncommon. You would have to dyna
mically insert a | 239 // This is potentially SLOW! But luckily very uncommon. You would have to |
229 // spanner into the middle of column contents to need this. | 240 // dynamically insert a spanner into the middle of column contents to need |
| 241 // this. |
230 for (; multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) { | 242 for (; multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) { |
231 LayoutObject* firstLayoutObject = firstLayoutObjectInSet(multicolSet); | 243 LayoutObject* firstLayoutObject = firstLayoutObjectInSet(multicolSet); |
232 LayoutObject* lastLayoutObject = lastLayoutObjectInSet(multicolSet); | 244 LayoutObject* lastLayoutObject = lastLayoutObjectInSet(multicolSet); |
233 ASSERT(firstLayoutObject); | 245 ASSERT(firstLayoutObject); |
234 | 246 |
235 for (LayoutObject* walker = firstLayoutObject; walker; | 247 for (LayoutObject* walker = firstLayoutObject; walker; |
236 walker = walker->nextInPreOrder(this)) { | 248 walker = walker->nextInPreOrder(this)) { |
237 if (walker == layoutObject) | 249 if (walker == layoutObject) |
238 return multicolSet; | 250 return multicolSet; |
239 if (walker == lastLayoutObject) | 251 if (walker == lastLayoutObject) |
240 break; | 252 break; |
241 } | 253 } |
242 } | 254 } |
243 | 255 |
244 return nullptr; | 256 return nullptr; |
245 } | 257 } |
246 | 258 |
247 LayoutMultiColumnSpannerPlaceholder* | 259 LayoutMultiColumnSpannerPlaceholder* |
248 LayoutMultiColumnFlowThread::containingColumnSpannerPlaceholder( | 260 LayoutMultiColumnFlowThread::containingColumnSpannerPlaceholder( |
249 const LayoutObject* descendant) const { | 261 const LayoutObject* descendant) const { |
250 ASSERT(descendant->isDescendantOf(this)); | 262 ASSERT(descendant->isDescendantOf(this)); |
251 | 263 |
252 if (!hasAnyColumnSpanners(*this)) | 264 if (!hasAnyColumnSpanners(*this)) |
253 return nullptr; | 265 return nullptr; |
254 | 266 |
255 // We have spanners. See if the layoutObject in question is one or inside of o
ne then. | 267 // We have spanners. See if the layoutObject in question is one or inside of |
| 268 // one then. |
256 for (const LayoutObject* ancestor = descendant; ancestor && ancestor != this; | 269 for (const LayoutObject* ancestor = descendant; ancestor && ancestor != this; |
257 ancestor = ancestor->parent()) { | 270 ancestor = ancestor->parent()) { |
258 if (LayoutMultiColumnSpannerPlaceholder* placeholder = | 271 if (LayoutMultiColumnSpannerPlaceholder* placeholder = |
259 ancestor->spannerPlaceholder()) | 272 ancestor->spannerPlaceholder()) |
260 return placeholder; | 273 return placeholder; |
261 } | 274 } |
262 return nullptr; | 275 return nullptr; |
263 } | 276 } |
264 | 277 |
265 void LayoutMultiColumnFlowThread::populate() { | 278 void LayoutMultiColumnFlowThread::populate() { |
266 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); | 279 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); |
267 ASSERT(!nextSibling()); | 280 ASSERT(!nextSibling()); |
268 // Reparent children preceding the flow thread into the flow thread. It's mult
icol content | 281 // Reparent children preceding the flow thread into the flow thread. It's |
269 // now. At this point there's obviously nothing after the flow thread, but lay
outObjects (column | 282 // multicol content now. At this point there's obviously nothing after the |
270 // sets and spanners) will be inserted there as we insert elements into the fl
ow thread. | 283 // flow thread, but layoutObjects (column sets and spanners) will be inserted |
| 284 // there as we insert elements into the flow thread. |
271 multicolContainer->removeFloatingObjectsFromDescendants(); | 285 multicolContainer->removeFloatingObjectsFromDescendants(); |
272 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), this, | 286 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), this, |
273 true); | 287 true); |
274 } | 288 } |
275 | 289 |
276 void LayoutMultiColumnFlowThread::evacuateAndDestroy() { | 290 void LayoutMultiColumnFlowThread::evacuateAndDestroy() { |
277 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); | 291 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); |
278 m_isBeingEvacuated = true; | 292 m_isBeingEvacuated = true; |
279 | 293 |
280 // Remove all sets and spanners. | 294 // Remove all sets and spanners. |
281 while (LayoutBox* columnBox = firstMultiColumnBox()) { | 295 while (LayoutBox* columnBox = firstMultiColumnBox()) { |
282 ASSERT(columnBox->isAnonymous()); | 296 ASSERT(columnBox->isAnonymous()); |
283 columnBox->destroy(); | 297 columnBox->destroy(); |
284 } | 298 } |
285 | 299 |
286 ASSERT(!previousSibling()); | 300 ASSERT(!previousSibling()); |
287 ASSERT(!nextSibling()); | 301 ASSERT(!nextSibling()); |
288 | 302 |
289 // Finally we can promote all flow thread's children. Before we move them to t
he flow thread's | 303 // Finally we can promote all flow thread's children. Before we move them to |
290 // container, we need to unregister the flow thread, so that they aren't just
re-added again to | 304 // the flow thread's container, we need to unregister the flow thread, so that |
291 // the flow thread that we're trying to empty. | 305 // they aren't just re-added again to the flow thread that we're trying to |
| 306 // empty. |
292 multicolContainer->resetMultiColumnFlowThread(); | 307 multicolContainer->resetMultiColumnFlowThread(); |
293 moveAllChildrenTo(multicolContainer, true); | 308 moveAllChildrenTo(multicolContainer, true); |
294 | 309 |
295 // We used to manually nuke the line box tree here, but that should happen aut
omatically when | 310 // We used to manually nuke the line box tree here, but that should happen |
296 // moving children around (the code above). | 311 // automatically when moving children around (the code above). |
297 ASSERT(!firstLineBox()); | 312 ASSERT(!firstLineBox()); |
298 | 313 |
299 destroy(); | 314 destroy(); |
300 } | 315 } |
301 | 316 |
302 LayoutUnit LayoutMultiColumnFlowThread::maxColumnLogicalHeight() const { | 317 LayoutUnit LayoutMultiColumnFlowThread::maxColumnLogicalHeight() const { |
303 if (m_columnHeightAvailable) { | 318 if (m_columnHeightAvailable) { |
304 // If height is non-auto, it's already constrained against max-height as wel
l. | 319 // If height is non-auto, it's already constrained against max-height as |
305 // Just return it. | 320 // well. Just return it. |
306 return m_columnHeightAvailable; | 321 return m_columnHeightAvailable; |
307 } | 322 } |
308 const LayoutBlockFlow* multicolBlock = multiColumnBlockFlow(); | 323 const LayoutBlockFlow* multicolBlock = multiColumnBlockFlow(); |
309 Length logicalMaxHeight = multicolBlock->style()->logicalMaxHeight(); | 324 Length logicalMaxHeight = multicolBlock->style()->logicalMaxHeight(); |
310 if (!logicalMaxHeight.isMaxSizeNone()) { | 325 if (!logicalMaxHeight.isMaxSizeNone()) { |
311 LayoutUnit resolvedLogicalMaxHeight = | 326 LayoutUnit resolvedLogicalMaxHeight = |
312 multicolBlock->computeContentLogicalHeight(MaxSize, logicalMaxHeight, | 327 multicolBlock->computeContentLogicalHeight(MaxSize, logicalMaxHeight, |
313 LayoutUnit(-1)); | 328 LayoutUnit(-1)); |
314 if (resolvedLogicalMaxHeight != -1) | 329 if (resolvedLogicalMaxHeight != -1) |
315 return resolvedLogicalMaxHeight; | 330 return resolvedLogicalMaxHeight; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 mode); | 373 mode); |
359 } | 374 } |
360 | 375 |
361 LayoutSize LayoutMultiColumnFlowThread::flowThreadTranslationAtPoint( | 376 LayoutSize LayoutMultiColumnFlowThread::flowThreadTranslationAtPoint( |
362 const LayoutPoint& flowThreadPoint, | 377 const LayoutPoint& flowThreadPoint, |
363 CoordinateSpaceConversion mode) const { | 378 CoordinateSpaceConversion mode) const { |
364 LayoutPoint flippedPoint = flipForWritingMode(flowThreadPoint); | 379 LayoutPoint flippedPoint = flipForWritingMode(flowThreadPoint); |
365 LayoutUnit blockOffset = | 380 LayoutUnit blockOffset = |
366 isHorizontalWritingMode() ? flippedPoint.y() : flippedPoint.x(); | 381 isHorizontalWritingMode() ? flippedPoint.y() : flippedPoint.x(); |
367 | 382 |
368 // If block direction is flipped, points at a column boundary belong in the fo
rmer column, not | 383 // If block direction is flipped, points at a column boundary belong in the |
369 // the latter. | 384 // former column, not the latter. |
370 PageBoundaryRule rule = hasFlippedBlocksWritingMode() | 385 PageBoundaryRule rule = hasFlippedBlocksWritingMode() |
371 ? AssociateWithFormerPage | 386 ? AssociateWithFormerPage |
372 : AssociateWithLatterPage; | 387 : AssociateWithLatterPage; |
373 | 388 |
374 return flowThreadTranslationAtOffset(blockOffset, rule, mode); | 389 return flowThreadTranslationAtOffset(blockOffset, rule, mode); |
375 } | 390 } |
376 | 391 |
377 LayoutPoint LayoutMultiColumnFlowThread::flowThreadPointToVisualPoint( | 392 LayoutPoint LayoutMultiColumnFlowThread::flowThreadPointToVisualPoint( |
378 const LayoutPoint& flowThreadPoint) const { | 393 const LayoutPoint& flowThreadPoint) const { |
379 return flowThreadPoint + | 394 return flowThreadPoint + |
(...skipping 29 matching lines...) Expand all Loading... |
409 return (baselineInFlowThread - | 424 return (baselineInFlowThread - |
410 columnSet->pageLogicalTopForOffset(baselineInFlowThread)) | 425 columnSet->pageLogicalTopForOffset(baselineInFlowThread)) |
411 .ceil(); | 426 .ceil(); |
412 } | 427 } |
413 | 428 |
414 LayoutMultiColumnSet* LayoutMultiColumnFlowThread::columnSetAtBlockOffset( | 429 LayoutMultiColumnSet* LayoutMultiColumnFlowThread::columnSetAtBlockOffset( |
415 LayoutUnit offset, | 430 LayoutUnit offset, |
416 PageBoundaryRule pageBoundaryRule) const { | 431 PageBoundaryRule pageBoundaryRule) const { |
417 LayoutMultiColumnSet* columnSet = m_lastSetWorkedOn; | 432 LayoutMultiColumnSet* columnSet = m_lastSetWorkedOn; |
418 if (columnSet) { | 433 if (columnSet) { |
419 // Layout in progress. We are calculating the set heights as we speak, so th
e column set range | 434 // Layout in progress. We are calculating the set heights as we speak, so |
420 // information is not up to date. | 435 // the column set range information is not up to date. |
421 while (columnSet->logicalTopInFlowThread() > offset) { | 436 while (columnSet->logicalTopInFlowThread() > offset) { |
422 // Sometimes we have to use a previous set. This happens when we're workin
g with a block | 437 // Sometimes we have to use a previous set. This happens when we're |
423 // that contains a spanner (so that there's a column set both before and a
fter the | 438 // working with a block that contains a spanner (so that there's a column |
424 // spanner, and both sets contain said block). | 439 // set both before and after the spanner, and both sets contain said |
| 440 // block). |
425 LayoutMultiColumnSet* previousSet = | 441 LayoutMultiColumnSet* previousSet = |
426 columnSet->previousSiblingMultiColumnSet(); | 442 columnSet->previousSiblingMultiColumnSet(); |
427 if (!previousSet) | 443 if (!previousSet) |
428 break; | 444 break; |
429 columnSet = previousSet; | 445 columnSet = previousSet; |
430 } | 446 } |
431 } else { | 447 } else { |
432 DCHECK(!m_columnSetsInvalidated); | 448 DCHECK(!m_columnSetsInvalidated); |
433 if (m_multiColumnSetList.isEmpty()) | 449 if (m_multiColumnSetList.isEmpty()) |
434 return nullptr; | 450 return nullptr; |
435 if (offset < LayoutUnit()) | 451 if (offset < LayoutUnit()) |
436 return m_multiColumnSetList.first(); | 452 return m_multiColumnSetList.first(); |
437 | 453 |
438 MultiColumnSetSearchAdapter adapter(offset); | 454 MultiColumnSetSearchAdapter adapter(offset); |
439 m_multiColumnSetIntervalTree | 455 m_multiColumnSetIntervalTree |
440 .allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter); | 456 .allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter); |
441 | 457 |
442 // If no set was found, the offset is in the flow thread overflow. | 458 // If no set was found, the offset is in the flow thread overflow. |
443 if (!adapter.result() && !m_multiColumnSetList.isEmpty()) | 459 if (!adapter.result() && !m_multiColumnSetList.isEmpty()) |
444 return m_multiColumnSetList.last(); | 460 return m_multiColumnSetList.last(); |
445 columnSet = adapter.result(); | 461 columnSet = adapter.result(); |
446 } | 462 } |
447 if (pageBoundaryRule == AssociateWithFormerPage && columnSet && | 463 if (pageBoundaryRule == AssociateWithFormerPage && columnSet && |
448 offset == columnSet->logicalTopInFlowThread()) { | 464 offset == columnSet->logicalTopInFlowThread()) { |
449 // The column set that we found starts at the exact same flow thread offset
as we specified. | 465 // The column set that we found starts at the exact same flow thread offset |
450 // Since we are to associate offsets at boundaries with the former fragmenta
iner, the | 466 // as we specified. Since we are to associate offsets at boundaries with the |
451 // fragmentainer we're looking for is in the previous column set. | 467 // former fragmentainer, the fragmentainer we're looking for is in the |
| 468 // previous column set. |
452 if (LayoutMultiColumnSet* previousSet = | 469 if (LayoutMultiColumnSet* previousSet = |
453 columnSet->previousSiblingMultiColumnSet()) | 470 columnSet->previousSiblingMultiColumnSet()) |
454 return previousSet; | 471 return previousSet; |
455 } | 472 } |
456 return columnSet; | 473 return columnSet; |
457 } | 474 } |
458 | 475 |
459 void LayoutMultiColumnFlowThread::layoutColumns( | 476 void LayoutMultiColumnFlowThread::layoutColumns( |
460 SubtreeLayoutScope& layoutScope) { | 477 SubtreeLayoutScope& layoutScope) { |
461 // Since we ended up here, it means that the multicol container (our parent) n
eeded | 478 // Since we ended up here, it means that the multicol container (our parent) |
462 // layout. Since contents of the multicol container are diverted to the flow t
hread, the flow | 479 // needed layout. Since contents of the multicol container are diverted to the |
463 // thread needs layout as well. | 480 // flow thread, the flow thread needs layout as well. |
464 layoutScope.setChildNeedsLayout(this); | 481 layoutScope.setChildNeedsLayout(this); |
465 | 482 |
466 if (FragmentationContext* enclosingFragmentationContext = | 483 if (FragmentationContext* enclosingFragmentationContext = |
467 this->enclosingFragmentationContext()) { | 484 this->enclosingFragmentationContext()) { |
468 m_blockOffsetInEnclosingFragmentationContext = | 485 m_blockOffsetInEnclosingFragmentationContext = |
469 multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage(); | 486 multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage(); |
470 m_blockOffsetInEnclosingFragmentationContext += | 487 m_blockOffsetInEnclosingFragmentationContext += |
471 multiColumnBlockFlow()->borderAndPaddingBefore(); | 488 multiColumnBlockFlow()->borderAndPaddingBefore(); |
472 | 489 |
473 if (LayoutMultiColumnFlowThread* enclosingFlowThread = | 490 if (LayoutMultiColumnFlowThread* enclosingFlowThread = |
474 enclosingFragmentationContext->associatedFlowThread()) { | 491 enclosingFragmentationContext->associatedFlowThread()) { |
475 if (LayoutMultiColumnSet* firstSet = firstMultiColumnSet()) { | 492 if (LayoutMultiColumnSet* firstSet = firstMultiColumnSet()) { |
476 // Before we can start to lay out the contents of this multicol containe
r, we need | 493 // Before we can start to lay out the contents of this multicol |
477 // to make sure that all ancestor multicol containers have established a
row to hold | 494 // container, we need to make sure that all ancestor multicol containers |
478 // the first column contents of this container (this multicol container
may start at | 495 // have established a row to hold the first column contents of this |
479 // the beginning of a new outer row). Without sufficient rows in all anc
estor | 496 // container (this multicol container may start at the beginning of a |
480 // multicol containers, we may use the wrong column height. | 497 // new outer row). Without sufficient rows in all ancestor multicol |
| 498 // containers, we may use the wrong column height. |
481 LayoutUnit offset = m_blockOffsetInEnclosingFragmentationContext + | 499 LayoutUnit offset = m_blockOffsetInEnclosingFragmentationContext + |
482 firstSet->logicalTopFromMulticolContentEdge(); | 500 firstSet->logicalTopFromMulticolContentEdge(); |
483 enclosingFlowThread->appendNewFragmentainerGroupIfNeeded( | 501 enclosingFlowThread->appendNewFragmentainerGroupIfNeeded( |
484 offset, AssociateWithLatterPage); | 502 offset, AssociateWithLatterPage); |
485 } | 503 } |
486 } | 504 } |
487 } | 505 } |
488 | 506 |
489 for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; | 507 for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; |
490 columnBox = columnBox->nextSiblingMultiColumnBox()) { | 508 columnBox = columnBox->nextSiblingMultiColumnBox()) { |
491 if (!columnBox->isLayoutMultiColumnSet()) { | 509 if (!columnBox->isLayoutMultiColumnSet()) { |
492 ASSERT( | 510 // No other type is expected. |
493 columnBox | 511 DCHECK(columnBox->isLayoutMultiColumnSpannerPlaceholder()); |
494 ->isLayoutMultiColumnSpannerPlaceholder()); // no other type is e
xpected. | |
495 continue; | 512 continue; |
496 } | 513 } |
497 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox); | 514 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox); |
498 layoutScope.setChildNeedsLayout(columnSet); | 515 layoutScope.setChildNeedsLayout(columnSet); |
499 if (!m_columnHeightsChanged) { | 516 if (!m_columnHeightsChanged) { |
500 // This is the initial layout pass. We need to reset the column height, be
cause contents | 517 // This is the initial layout pass. We need to reset the column height, |
501 // typically have changed. | 518 // because contents typically have changed. |
502 columnSet->resetColumnHeight(); | 519 columnSet->resetColumnHeight(); |
503 } | 520 } |
504 // Since column sets are regular block flow objects, and their position is c
hanged in | 521 // Since column sets are regular block flow objects, and their position is |
505 // regular block layout code (with no means for the multicol code to notice
unless we add | 522 // changed in regular block layout code (with no means for the multicol code |
506 // hooks there), store the previous position now. If it changes in the immin
ent layout | 523 // to notice unless we add hooks there), store the previous position now. If |
507 // pass, we may have to rebalance its columns. | 524 // it changes in the imminent layout pass, we may have to rebalance its |
| 525 // columns. |
508 columnSet->storeOldPosition(); | 526 columnSet->storeOldPosition(); |
509 } | 527 } |
510 | 528 |
511 m_columnHeightsChanged = false; | 529 m_columnHeightsChanged = false; |
512 invalidateColumnSets(); | 530 invalidateColumnSets(); |
513 layout(); | 531 layout(); |
514 validateColumnSets(); | 532 validateColumnSets(); |
515 } | 533 } |
516 | 534 |
517 void LayoutMultiColumnFlowThread::columnRuleStyleDidChange() { | 535 void LayoutMultiColumnFlowThread::columnRuleStyleDidChange() { |
518 for (LayoutMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; | 536 for (LayoutMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; |
519 columnSet = columnSet->nextSiblingMultiColumnSet()) | 537 columnSet = columnSet->nextSiblingMultiColumnSet()) |
520 columnSet->setShouldDoFullPaintInvalidation(PaintInvalidationStyleChange); | 538 columnSet->setShouldDoFullPaintInvalidation(PaintInvalidationStyleChange); |
521 } | 539 } |
522 | 540 |
523 bool LayoutMultiColumnFlowThread::removeSpannerPlaceholderIfNoLongerValid( | 541 bool LayoutMultiColumnFlowThread::removeSpannerPlaceholderIfNoLongerValid( |
524 LayoutBox* spannerObjectInFlowThread) { | 542 LayoutBox* spannerObjectInFlowThread) { |
525 ASSERT(spannerObjectInFlowThread->spannerPlaceholder()); | 543 ASSERT(spannerObjectInFlowThread->spannerPlaceholder()); |
526 if (descendantIsValidColumnSpanner(spannerObjectInFlowThread)) | 544 if (descendantIsValidColumnSpanner(spannerObjectInFlowThread)) |
527 return false; // Still a valid spanner. | 545 return false; // Still a valid spanner. |
528 | 546 |
529 // No longer a valid spanner. Get rid of the placeholder. | 547 // No longer a valid spanner. Get rid of the placeholder. |
530 destroySpannerPlaceholder(spannerObjectInFlowThread->spannerPlaceholder()); | 548 destroySpannerPlaceholder(spannerObjectInFlowThread->spannerPlaceholder()); |
531 ASSERT(!spannerObjectInFlowThread->spannerPlaceholder()); | 549 ASSERT(!spannerObjectInFlowThread->spannerPlaceholder()); |
532 | 550 |
533 // We may have a new containing block, since we're no longer a spanner. Mark i
t for relayout. | 551 // We may have a new containing block, since we're no longer a spanner. Mark |
| 552 // it for relayout. |
534 spannerObjectInFlowThread->containingBlock() | 553 spannerObjectInFlowThread->containingBlock() |
535 ->setNeedsLayoutAndPrefWidthsRecalc( | 554 ->setNeedsLayoutAndPrefWidthsRecalc( |
536 LayoutInvalidationReason::ColumnsChanged); | 555 LayoutInvalidationReason::ColumnsChanged); |
537 | 556 |
538 // Now generate a column set for this ex-spanner, if needed and none is there
for us already. | 557 // Now generate a column set for this ex-spanner, if needed and none is there |
| 558 // for us already. |
539 flowThreadDescendantWasInserted(spannerObjectInFlowThread); | 559 flowThreadDescendantWasInserted(spannerObjectInFlowThread); |
540 | 560 |
541 return true; | 561 return true; |
542 } | 562 } |
543 | 563 |
544 LayoutMultiColumnFlowThread* LayoutMultiColumnFlowThread::enclosingFlowThread() | 564 LayoutMultiColumnFlowThread* LayoutMultiColumnFlowThread::enclosingFlowThread() |
545 const { | 565 const { |
546 if (isLayoutPagedFlowThread()) { | 566 if (isLayoutPagedFlowThread()) { |
547 // Paged overflow containers should never be fragmented by enclosing fragmen
tation | 567 // Paged overflow containers should never be fragmented by enclosing |
548 // contexts. They are to be treated as unbreakable content. | 568 // fragmentation contexts. They are to be treated as unbreakable content. |
549 return nullptr; | 569 return nullptr; |
550 } | 570 } |
551 if (multiColumnBlockFlow()->isInsideFlowThread()) | 571 if (multiColumnBlockFlow()->isInsideFlowThread()) |
552 return toLayoutMultiColumnFlowThread( | 572 return toLayoutMultiColumnFlowThread( |
553 locateFlowThreadContainingBlockOf(*multiColumnBlockFlow())); | 573 locateFlowThreadContainingBlockOf(*multiColumnBlockFlow())); |
554 return nullptr; | 574 return nullptr; |
555 } | 575 } |
556 | 576 |
557 FragmentationContext* | 577 FragmentationContext* |
558 LayoutMultiColumnFlowThread::enclosingFragmentationContext() const { | 578 LayoutMultiColumnFlowThread::enclosingFragmentationContext() const { |
559 if (LayoutMultiColumnFlowThread* enclosingFlowThread = | 579 if (LayoutMultiColumnFlowThread* enclosingFlowThread = |
560 this->enclosingFlowThread()) | 580 this->enclosingFlowThread()) |
561 return enclosingFlowThread; | 581 return enclosingFlowThread; |
562 return view()->fragmentationContext(); | 582 return view()->fragmentationContext(); |
563 } | 583 } |
564 | 584 |
565 void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded( | 585 void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded( |
566 LayoutUnit offsetInFlowThread, | 586 LayoutUnit offsetInFlowThread, |
567 PageBoundaryRule pageBoundaryRule) { | 587 PageBoundaryRule pageBoundaryRule) { |
568 if (!isPageLogicalHeightKnown()) { | 588 if (!isPageLogicalHeightKnown()) { |
569 // If we have no clue about the height of the multicol container, bail. This
situation | 589 // If we have no clue about the height of the multicol container, bail. This |
570 // occurs initially when an auto-height multicol container is nested inside
another | 590 // situation occurs initially when an auto-height multicol container is |
571 // auto-height multicol container. We need at least an estimated height of t
he outer | 591 // nested inside another auto-height multicol container. We need at least an |
572 // multicol container before we can check what an inner fragmentainer group
has room for. | 592 // estimated height of the outer multicol container before we can check what |
| 593 // an inner fragmentainer group has room for. |
573 // Its height is indefinite for now. | 594 // Its height is indefinite for now. |
574 return; | 595 return; |
575 } | 596 } |
576 LayoutMultiColumnSet* columnSet = | 597 LayoutMultiColumnSet* columnSet = |
577 columnSetAtBlockOffset(offsetInFlowThread, pageBoundaryRule); | 598 columnSetAtBlockOffset(offsetInFlowThread, pageBoundaryRule); |
578 if (columnSet->isInitialHeightCalculated()) { | 599 if (columnSet->isInitialHeightCalculated()) { |
579 // We only insert additional fragmentainer groups in the initial layout pass
. We only want | 600 // We only insert additional fragmentainer groups in the initial layout |
580 // to balance columns in the last fragmentainer group (if we need to balance
at all), so we | 601 // pass. We only want to balance columns in the last fragmentainer group (if |
581 // want that last fragmentainer group to be the same one in all layout passe
s that follow. | 602 // we need to balance at all), so we want that last fragmentainer group to |
| 603 // be the same one in all layout passes that follow. |
582 return; | 604 return; |
583 } | 605 } |
584 | 606 |
585 if (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread, | 607 if (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread, |
586 pageBoundaryRule)) { | 608 pageBoundaryRule)) { |
587 FragmentationContext* enclosingFragmentationContext = | 609 FragmentationContext* enclosingFragmentationContext = |
588 this->enclosingFragmentationContext(); | 610 this->enclosingFragmentationContext(); |
| 611 // Not nested. We'll never need more rows than the one we already have then. |
589 if (!enclosingFragmentationContext) | 612 if (!enclosingFragmentationContext) |
590 return; // Not nested. We'll never need more rows than the one we already
have then. | 613 return; |
591 ASSERT(!isLayoutPagedFlowThread()); | 614 ASSERT(!isLayoutPagedFlowThread()); |
592 | 615 |
593 // We have run out of columns here, so we need to add at least one more row
to hold more | 616 // We have run out of columns here, so we need to add at least one more row |
594 // columns. | 617 // to hold more columns. |
595 LayoutMultiColumnFlowThread* enclosingFlowThread = | 618 LayoutMultiColumnFlowThread* enclosingFlowThread = |
596 enclosingFragmentationContext->associatedFlowThread(); | 619 enclosingFragmentationContext->associatedFlowThread(); |
597 do { | 620 do { |
598 if (enclosingFlowThread) { | 621 if (enclosingFlowThread) { |
599 // When we add a new row here, it implicitly means that we're inserting
another | 622 // When we add a new row here, it implicitly means that we're inserting |
600 // column in our enclosing multicol container. That in turn may mean tha
t we've run | 623 // another column in our enclosing multicol container. That in turn may |
601 // out of columns there too. Need to insert additional rows in ancestral
multicol | 624 // mean that we've run out of columns there too. Need to insert |
602 // containers before doing it in the descendants, in order to get the he
ight | 625 // additional rows in ancestral multicol containers before doing it in |
603 // constraints right down there. | 626 // the descendants, in order to get the height constraints right down |
| 627 // there. |
604 const MultiColumnFragmentainerGroup& lastRow = | 628 const MultiColumnFragmentainerGroup& lastRow = |
605 columnSet->lastFragmentainerGroup(); | 629 columnSet->lastFragmentainerGroup(); |
606 // The top offset where where the new fragmentainer group will start in
this column | 630 // The top offset where where the new fragmentainer group will start in |
607 // set, converted to the coordinate space of the enclosing multicol cont
ainer. | 631 // this column set, converted to the coordinate space of the enclosing |
| 632 // multicol container. |
608 LayoutUnit logicalOffsetInOuter = | 633 LayoutUnit logicalOffsetInOuter = |
609 lastRow.blockOffsetInEnclosingFragmentationContext() + | 634 lastRow.blockOffsetInEnclosingFragmentationContext() + |
610 lastRow.logicalHeight(); | 635 lastRow.logicalHeight(); |
611 enclosingFlowThread->appendNewFragmentainerGroupIfNeeded( | 636 enclosingFlowThread->appendNewFragmentainerGroupIfNeeded( |
612 logicalOffsetInOuter, AssociateWithLatterPage); | 637 logicalOffsetInOuter, AssociateWithLatterPage); |
613 } | 638 } |
614 | 639 |
615 const MultiColumnFragmentainerGroup& newRow = | 640 const MultiColumnFragmentainerGroup& newRow = |
616 columnSet->appendNewFragmentainerGroup(); | 641 columnSet->appendNewFragmentainerGroup(); |
617 // Zero-height rows should really not occur here, but if it does anyway, b
reak, so that | 642 // Zero-height rows should really not occur here, but if it does anyway, |
618 // we don't get stuck in an infinite loop. | 643 // break, so that we don't get stuck in an infinite loop. |
619 ASSERT(newRow.logicalHeight() > 0); | 644 ASSERT(newRow.logicalHeight() > 0); |
620 if (newRow.logicalHeight() <= 0) | 645 if (newRow.logicalHeight() <= 0) |
621 break; | 646 break; |
622 } while (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread, | 647 } while (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread, |
623 pageBoundaryRule)); | 648 pageBoundaryRule)); |
624 } | 649 } |
625 } | 650 } |
626 | 651 |
627 bool LayoutMultiColumnFlowThread::isFragmentainerLogicalHeightKnown() { | 652 bool LayoutMultiColumnFlowThread::isFragmentainerLogicalHeightKnown() { |
628 return isPageLogicalHeightKnown(); | 653 return isPageLogicalHeightKnown(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 } | 698 } |
674 | 699 |
675 void LayoutMultiColumnFlowThread::createAndInsertMultiColumnSet( | 700 void LayoutMultiColumnFlowThread::createAndInsertMultiColumnSet( |
676 LayoutBox* insertBefore) { | 701 LayoutBox* insertBefore) { |
677 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); | 702 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); |
678 LayoutMultiColumnSet* newSet = LayoutMultiColumnSet::createAnonymous( | 703 LayoutMultiColumnSet* newSet = LayoutMultiColumnSet::createAnonymous( |
679 *this, multicolContainer->styleRef()); | 704 *this, multicolContainer->styleRef()); |
680 multicolContainer->LayoutBlock::addChild(newSet, insertBefore); | 705 multicolContainer->LayoutBlock::addChild(newSet, insertBefore); |
681 invalidateColumnSets(); | 706 invalidateColumnSets(); |
682 | 707 |
683 // We cannot handle immediate column set siblings (and there's no need for it,
either). | 708 // We cannot handle immediate column set siblings (and there's no need for it, |
684 // There has to be at least one spanner separating them. | 709 // either). There has to be at least one spanner separating them. |
685 ASSERT(!newSet->previousSiblingMultiColumnBox() || | 710 ASSERT(!newSet->previousSiblingMultiColumnBox() || |
686 !newSet->previousSiblingMultiColumnBox()->isLayoutMultiColumnSet()); | 711 !newSet->previousSiblingMultiColumnBox()->isLayoutMultiColumnSet()); |
687 ASSERT(!newSet->nextSiblingMultiColumnBox() || | 712 ASSERT(!newSet->nextSiblingMultiColumnBox() || |
688 !newSet->nextSiblingMultiColumnBox()->isLayoutMultiColumnSet()); | 713 !newSet->nextSiblingMultiColumnBox()->isLayoutMultiColumnSet()); |
689 } | 714 } |
690 | 715 |
691 void LayoutMultiColumnFlowThread::createAndInsertSpannerPlaceholder( | 716 void LayoutMultiColumnFlowThread::createAndInsertSpannerPlaceholder( |
692 LayoutBox* spannerObjectInFlowThread, | 717 LayoutBox* spannerObjectInFlowThread, |
693 LayoutObject* insertedBeforeInFlowThread) { | 718 LayoutObject* insertedBeforeInFlowThread) { |
694 LayoutBox* insertBeforeColumnBox = nullptr; | 719 LayoutBox* insertBeforeColumnBox = nullptr; |
695 LayoutMultiColumnSet* setToSplit = nullptr; | 720 LayoutMultiColumnSet* setToSplit = nullptr; |
696 if (insertedBeforeInFlowThread) { | 721 if (insertedBeforeInFlowThread) { |
697 // The spanner is inserted before something. Figure out what this entails. I
f the | 722 // The spanner is inserted before something. Figure out what this entails. |
698 // next object is a spanner too, it means that we can simply insert a new sp
anner | 723 // If the next object is a spanner too, it means that we can simply insert a |
699 // placeholder in front of its placeholder. | 724 // new spanner placeholder in front of its placeholder. |
700 insertBeforeColumnBox = insertedBeforeInFlowThread->spannerPlaceholder(); | 725 insertBeforeColumnBox = insertedBeforeInFlowThread->spannerPlaceholder(); |
701 if (!insertBeforeColumnBox) { | 726 if (!insertBeforeColumnBox) { |
702 // The next object isn't a spanner; it's regular column content. Examine w
hat | 727 // The next object isn't a spanner; it's regular column content. Examine |
703 // comes right before us in the flow thread, then. | 728 // what comes right before us in the flow thread, then. |
704 LayoutObject* previousLayoutObject = | 729 LayoutObject* previousLayoutObject = |
705 previousInPreOrderSkippingOutOfFlow(this, spannerObjectInFlowThread); | 730 previousInPreOrderSkippingOutOfFlow(this, spannerObjectInFlowThread); |
706 if (!previousLayoutObject || previousLayoutObject == this) { | 731 if (!previousLayoutObject || previousLayoutObject == this) { |
707 // The spanner is inserted as the first child of the multicol container, | 732 // The spanner is inserted as the first child of the multicol container, |
708 // which means that we simply insert a new spanner placeholder at the | 733 // which means that we simply insert a new spanner placeholder at the |
709 // beginning. | 734 // beginning. |
710 insertBeforeColumnBox = firstMultiColumnBox(); | 735 insertBeforeColumnBox = firstMultiColumnBox(); |
711 } else if (LayoutMultiColumnSpannerPlaceholder* previousPlaceholder = | 736 } else if (LayoutMultiColumnSpannerPlaceholder* previousPlaceholder = |
712 containingColumnSpannerPlaceholder(previousLayoutObject)) { | 737 containingColumnSpannerPlaceholder(previousLayoutObject)) { |
713 // Before us is another spanner. We belong right after it then. | 738 // Before us is another spanner. We belong right after it then. |
714 insertBeforeColumnBox = | 739 insertBeforeColumnBox = |
715 previousPlaceholder->nextSiblingMultiColumnBox(); | 740 previousPlaceholder->nextSiblingMultiColumnBox(); |
716 } else { | 741 } else { |
717 // We're inside regular column content with both feet. Find out which co
lumn | 742 // We're inside regular column content with both feet. Find out which |
718 // set this is. It needs to be split it into two sets, so that we can in
sert | 743 // column set this is. It needs to be split it into two sets, so that we |
719 // a new spanner placeholder between them. | 744 // can insert a new spanner placeholder between them. |
720 setToSplit = mapDescendantToColumnSet(previousLayoutObject); | 745 setToSplit = mapDescendantToColumnSet(previousLayoutObject); |
721 ASSERT(setToSplit == | 746 ASSERT(setToSplit == |
722 mapDescendantToColumnSet(insertedBeforeInFlowThread)); | 747 mapDescendantToColumnSet(insertedBeforeInFlowThread)); |
723 insertBeforeColumnBox = setToSplit->nextSiblingMultiColumnBox(); | 748 insertBeforeColumnBox = setToSplit->nextSiblingMultiColumnBox(); |
724 // We've found out which set that needs to be split. Now proceed to | 749 // We've found out which set that needs to be split. Now proceed to |
725 // inserting the spanner placeholder, and then insert a second column se
t. | 750 // inserting the spanner placeholder, and then insert a second column |
| 751 // set. |
726 } | 752 } |
727 } | 753 } |
728 ASSERT(setToSplit || insertBeforeColumnBox); | 754 ASSERT(setToSplit || insertBeforeColumnBox); |
729 } | 755 } |
730 | 756 |
731 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); | 757 LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); |
732 LayoutMultiColumnSpannerPlaceholder* newPlaceholder = | 758 LayoutMultiColumnSpannerPlaceholder* newPlaceholder = |
733 LayoutMultiColumnSpannerPlaceholder::createAnonymous( | 759 LayoutMultiColumnSpannerPlaceholder::createAnonymous( |
734 multicolContainer->styleRef(), *spannerObjectInFlowThread); | 760 multicolContainer->styleRef(), *spannerObjectInFlowThread); |
735 ASSERT(!insertBeforeColumnBox || | 761 ASSERT(!insertBeforeColumnBox || |
(...skipping 16 matching lines...) Expand all Loading... |
752 nextColumnBox->destroy(); | 778 nextColumnBox->destroy(); |
753 invalidateColumnSets(); | 779 invalidateColumnSets(); |
754 } | 780 } |
755 } | 781 } |
756 placeholder->destroy(); | 782 placeholder->destroy(); |
757 } | 783 } |
758 | 784 |
759 bool LayoutMultiColumnFlowThread::descendantIsValidColumnSpanner( | 785 bool LayoutMultiColumnFlowThread::descendantIsValidColumnSpanner( |
760 LayoutObject* descendant) const { | 786 LayoutObject* descendant) const { |
761 // This method needs to behave correctly in the following situations: | 787 // This method needs to behave correctly in the following situations: |
762 // - When the descendant doesn't have a spanner placeholder but should have on
e (return true) | 788 // - When the descendant doesn't have a spanner placeholder but should have |
763 // - When the descendant doesn't have a spanner placeholder and still should n
ot have one (return false) | 789 // one (return true). |
764 // - When the descendant has a spanner placeholder but should no longer have o
ne (return false) | 790 // - When the descendant doesn't have a spanner placeholder and still should |
765 // - When the descendant has a spanner placeholder and should still have one (
return true) | 791 // not have one (return false). |
| 792 // - When the descendant has a spanner placeholder but should no longer have |
| 793 // one (return false). |
| 794 // - When the descendant has a spanner placeholder and should still have one |
| 795 // (return true). |
766 | 796 |
767 // We assume that we're inside the flow thread. This function is not to be cal
led otherwise. | 797 // We assume that we're inside the flow thread. This function is not to be |
| 798 // called otherwise. |
768 ASSERT(descendant->isDescendantOf(this)); | 799 ASSERT(descendant->isDescendantOf(this)); |
769 | 800 |
770 // The spec says that column-span only applies to in-flow block-level elements
. | 801 // The spec says that column-span only applies to in-flow block-level |
| 802 // elements. |
771 if (descendant->style()->getColumnSpan() != ColumnSpanAll || | 803 if (descendant->style()->getColumnSpan() != ColumnSpanAll || |
772 !descendant->isBox() || descendant->isInline() || | 804 !descendant->isBox() || descendant->isInline() || |
773 descendant->isFloatingOrOutOfFlowPositioned()) | 805 descendant->isFloatingOrOutOfFlowPositioned()) |
774 return false; | 806 return false; |
775 | 807 |
776 if (!descendant->containingBlock()->isLayoutBlockFlow()) { | 808 if (!descendant->containingBlock()->isLayoutBlockFlow()) { |
777 // Needs to be in a block-flow container, and not e.g. a table. | 809 // Needs to be in a block-flow container, and not e.g. a table. |
778 return false; | 810 return false; |
779 } | 811 } |
780 | 812 |
781 // This looks like a spanner, but if we're inside something unbreakable or som
ething that | 813 // This looks like a spanner, but if we're inside something unbreakable or |
782 // establishes a new formatting context, it's not to be treated as one. | 814 // something that establishes a new formatting context, it's not to be treated |
| 815 // as one. |
783 for (LayoutBox* ancestor = toLayoutBox(descendant)->parentBox(); ancestor; | 816 for (LayoutBox* ancestor = toLayoutBox(descendant)->parentBox(); ancestor; |
784 ancestor = ancestor->containingBlock()) { | 817 ancestor = ancestor->containingBlock()) { |
785 if (ancestor->isLayoutFlowThread()) { | 818 if (ancestor->isLayoutFlowThread()) { |
786 ASSERT(ancestor == this); | 819 ASSERT(ancestor == this); |
787 return true; | 820 return true; |
788 } | 821 } |
789 if (!canContainSpannerInParentFragmentationContext(*ancestor)) | 822 if (!canContainSpannerInParentFragmentationContext(*ancestor)) |
790 return false; | 823 return false; |
791 } | 824 } |
792 ASSERT_NOT_REACHED(); | 825 ASSERT_NOT_REACHED(); |
793 return false; | 826 return false; |
794 } | 827 } |
795 | 828 |
796 void LayoutMultiColumnFlowThread::addColumnSetToThread( | 829 void LayoutMultiColumnFlowThread::addColumnSetToThread( |
797 LayoutMultiColumnSet* columnSet) { | 830 LayoutMultiColumnSet* columnSet) { |
798 if (LayoutMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) { | 831 if (LayoutMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) { |
799 LayoutMultiColumnSetList::iterator it = m_multiColumnSetList.find(nextSet); | 832 LayoutMultiColumnSetList::iterator it = m_multiColumnSetList.find(nextSet); |
800 ASSERT(it != m_multiColumnSetList.end()); | 833 ASSERT(it != m_multiColumnSetList.end()); |
801 m_multiColumnSetList.insertBefore(it, columnSet); | 834 m_multiColumnSetList.insertBefore(it, columnSet); |
802 } else { | 835 } else { |
803 m_multiColumnSetList.add(columnSet); | 836 m_multiColumnSetList.add(columnSet); |
804 } | 837 } |
805 } | 838 } |
806 | 839 |
807 void LayoutMultiColumnFlowThread::willBeRemovedFromTree() { | 840 void LayoutMultiColumnFlowThread::willBeRemovedFromTree() { |
808 // Detach all column sets from the flow thread. Cannot destroy them at this po
int, since they | 841 // Detach all column sets from the flow thread. Cannot destroy them at this |
809 // are siblings of this object, and there may be pointers to this object's sib
ling somewhere | 842 // point, since they are siblings of this object, and there may be pointers to |
810 // further up on the call stack. | 843 // this object's sibling somewhere further up on the call stack. |
811 for (LayoutMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; | 844 for (LayoutMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; |
812 columnSet = columnSet->nextSiblingMultiColumnSet()) | 845 columnSet = columnSet->nextSiblingMultiColumnSet()) |
813 columnSet->detachFromFlowThread(); | 846 columnSet->detachFromFlowThread(); |
814 multiColumnBlockFlow()->resetMultiColumnFlowThread(); | 847 multiColumnBlockFlow()->resetMultiColumnFlowThread(); |
815 LayoutFlowThread::willBeRemovedFromTree(); | 848 LayoutFlowThread::willBeRemovedFromTree(); |
816 } | 849 } |
817 | 850 |
818 void LayoutMultiColumnFlowThread::skipColumnSpanner( | 851 void LayoutMultiColumnFlowThread::skipColumnSpanner( |
819 LayoutBox* layoutObject, | 852 LayoutBox* layoutObject, |
820 LayoutUnit logicalTopInFlowThread) { | 853 LayoutUnit logicalTopInFlowThread) { |
821 ASSERT(layoutObject->isColumnSpanAll()); | 854 ASSERT(layoutObject->isColumnSpanAll()); |
822 LayoutMultiColumnSpannerPlaceholder* placeholder = | 855 LayoutMultiColumnSpannerPlaceholder* placeholder = |
823 layoutObject->spannerPlaceholder(); | 856 layoutObject->spannerPlaceholder(); |
824 LayoutBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); | 857 LayoutBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); |
825 if (previousColumnBox && previousColumnBox->isLayoutMultiColumnSet()) { | 858 if (previousColumnBox && previousColumnBox->isLayoutMultiColumnSet()) { |
826 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(previousColumnBox); | 859 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(previousColumnBox); |
| 860 // Negative margins may cause this. |
827 if (logicalTopInFlowThread < columnSet->logicalTopInFlowThread()) | 861 if (logicalTopInFlowThread < columnSet->logicalTopInFlowThread()) |
828 logicalTopInFlowThread = | 862 logicalTopInFlowThread = columnSet->logicalTopInFlowThread(); |
829 columnSet | |
830 ->logicalTopInFlowThread(); // Negative margins may cause this. | |
831 columnSet->endFlow(logicalTopInFlowThread); | 863 columnSet->endFlow(logicalTopInFlowThread); |
832 } | 864 } |
833 LayoutBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox(); | 865 LayoutBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox(); |
834 if (nextColumnBox && nextColumnBox->isLayoutMultiColumnSet()) { | 866 if (nextColumnBox && nextColumnBox->isLayoutMultiColumnSet()) { |
835 LayoutMultiColumnSet* nextSet = toLayoutMultiColumnSet(nextColumnBox); | 867 LayoutMultiColumnSet* nextSet = toLayoutMultiColumnSet(nextColumnBox); |
836 m_lastSetWorkedOn = nextSet; | 868 m_lastSetWorkedOn = nextSet; |
837 nextSet->beginFlow(logicalTopInFlowThread); | 869 nextSet->beginFlow(logicalTopInFlowThread); |
838 } | 870 } |
839 | 871 |
840 // We'll lay out of spanners after flow thread layout has finished (during lay
out of the spanner | 872 // We'll lay out of spanners after flow thread layout has finished (during |
841 // placeholders). There may be containing blocks for out-of-flow positioned de
scendants of the | 873 // layout of the spanner placeholders). There may be containing blocks for |
842 // spanner in the flow thread, so that out-of-flow objects inside the spanner
will be laid out | 874 // out-of-flow positioned descendants of the spanner in the flow thread, so |
843 // as part of flow thread layout (even if the spanner itself won't). We need t
o add such | 875 // that out-of-flow objects inside the spanner will be laid out as part of |
844 // out-of-flow positioned objects to their containing blocks now, or they'll n
ever get laid | 876 // flow thread layout (even if the spanner itself won't). We need to add such |
845 // out. Since it's non-trivial to determine if we need this, and where such ou
t-of-flow objects | 877 // out-of-flow positioned objects to their containing blocks now, or they'll |
846 // might be, just go through the whole subtree. | 878 // never get laid out. Since it's non-trivial to determine if we need this, |
| 879 // and where such out-of-flow objects might be, just go through the whole |
| 880 // subtree. |
847 for (LayoutObject* descendant = layoutObject->slowFirstChild(); descendant; | 881 for (LayoutObject* descendant = layoutObject->slowFirstChild(); descendant; |
848 descendant = descendant->nextInPreOrder()) { | 882 descendant = descendant->nextInPreOrder()) { |
849 if (descendant->isBox() && descendant->isOutOfFlowPositioned()) | 883 if (descendant->isBox() && descendant->isOutOfFlowPositioned()) |
850 descendant->containingBlock()->insertPositionedObject( | 884 descendant->containingBlock()->insertPositionedObject( |
851 toLayoutBox(descendant)); | 885 toLayoutBox(descendant)); |
852 } | 886 } |
853 } | 887 } |
854 | 888 |
855 // When processing layout objects to remove or when processing layout objects th
at have just been | 889 // When processing layout objects to remove or when processing layout objects |
856 // inserted, certain types of objects should be skipped. | 890 // that have just been inserted, certain types of objects should be skipped. |
857 static bool shouldSkipInsertedOrRemovedChild( | 891 static bool shouldSkipInsertedOrRemovedChild( |
858 LayoutMultiColumnFlowThread* flowThread, | 892 LayoutMultiColumnFlowThread* flowThread, |
859 const LayoutObject& child) { | 893 const LayoutObject& child) { |
860 if (child.isSVG() && !child.isSVGRoot()) { | 894 if (child.isSVG() && !child.isSVGRoot()) { |
861 // Don't descend into SVG objects. What's in there is of no interest, and th
ere might even | 895 // Don't descend into SVG objects. What's in there is of no interest, and |
862 // be a foreignObject there with column-span:all, which doesn't apply to us. | 896 // there might even be a foreignObject there with column-span:all, which |
| 897 // doesn't apply to us. |
863 return true; | 898 return true; |
864 } | 899 } |
865 if (child.isLayoutFlowThread()) { | 900 if (child.isLayoutFlowThread()) { |
866 // Found an inner flow thread. We need to skip it and its descendants. | 901 // Found an inner flow thread. We need to skip it and its descendants. |
867 return true; | 902 return true; |
868 } | 903 } |
869 if (child.isLayoutMultiColumnSet() || | 904 if (child.isLayoutMultiColumnSet() || |
870 child.isLayoutMultiColumnSpannerPlaceholder()) { | 905 child.isLayoutMultiColumnSpannerPlaceholder()) { |
871 // Column sets and spanner placeholders in a child multicol context don't af
fect the parent | 906 // Column sets and spanner placeholders in a child multicol context don't |
872 // flow thread. | 907 // affect the parent flow thread. |
873 return true; | 908 return true; |
874 } | 909 } |
875 if (child.isOutOfFlowPositioned() && | 910 if (child.isOutOfFlowPositioned() && |
876 child.containingBlock()->flowThreadContainingBlock() != flowThread) { | 911 child.containingBlock()->flowThreadContainingBlock() != flowThread) { |
877 // Out-of-flow with its containing block on the outside of the multicol cont
ainer. | 912 // Out-of-flow with its containing block on the outside of the multicol |
| 913 // container. |
878 return true; | 914 return true; |
879 } | 915 } |
880 return false; | 916 return false; |
881 } | 917 } |
882 | 918 |
883 void LayoutMultiColumnFlowThread::flowThreadDescendantWasInserted( | 919 void LayoutMultiColumnFlowThread::flowThreadDescendantWasInserted( |
884 LayoutObject* descendant) { | 920 LayoutObject* descendant) { |
885 ASSERT(!m_isBeingEvacuated); | 921 ASSERT(!m_isBeingEvacuated); |
886 // This method ensures that the list of column sets and spanner placeholders r
eflects the | 922 // This method ensures that the list of column sets and spanner placeholders |
887 // multicol content after having inserted a descendant (or descendant subtree)
. See the header | 923 // reflects the multicol content after having inserted a descendant (or |
888 // file for more information. Go through the subtree that was just inserted an
d create column | 924 // descendant subtree). See the header file for more information. Go through |
889 // sets (needed by regular column content) and spanner placeholders (one neede
d by each spanner) | 925 // the subtree that was just inserted and create column sets (needed by |
890 // where needed. | 926 // regular column content) and spanner placeholders (one needed by each |
| 927 // spanner) where needed. |
891 if (shouldSkipInsertedOrRemovedChild(this, *descendant)) | 928 if (shouldSkipInsertedOrRemovedChild(this, *descendant)) |
892 return; | 929 return; |
893 LayoutObject* objectAfterSubtree = | 930 LayoutObject* objectAfterSubtree = |
894 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); | 931 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); |
895 LayoutObject* next; | 932 LayoutObject* next; |
896 for (LayoutObject* layoutObject = descendant; layoutObject; | 933 for (LayoutObject* layoutObject = descendant; layoutObject; |
897 layoutObject = next) { | 934 layoutObject = next) { |
898 if (layoutObject != descendant && | 935 if (layoutObject != descendant && |
899 shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { | 936 shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { |
900 next = layoutObject->nextInPreOrderAfterChildren(descendant); | 937 next = layoutObject->nextInPreOrderAfterChildren(descendant); |
901 continue; | 938 continue; |
902 } | 939 } |
903 next = layoutObject->nextInPreOrder(descendant); | 940 next = layoutObject->nextInPreOrder(descendant); |
904 if (containingColumnSpannerPlaceholder(layoutObject)) | 941 if (containingColumnSpannerPlaceholder(layoutObject)) |
905 continue; // Inside a column spanner. Nothing to do, then. | 942 continue; // Inside a column spanner. Nothing to do, then. |
906 if (descendantIsValidColumnSpanner(layoutObject)) { | 943 if (descendantIsValidColumnSpanner(layoutObject)) { |
907 // This layoutObject is a spanner, so it needs to establish a spanner plac
eholder. | 944 // This layoutObject is a spanner, so it needs to establish a spanner |
| 945 // placeholder. |
908 createAndInsertSpannerPlaceholder(toLayoutBox(layoutObject), | 946 createAndInsertSpannerPlaceholder(toLayoutBox(layoutObject), |
909 objectAfterSubtree); | 947 objectAfterSubtree); |
910 continue; | 948 continue; |
911 } | 949 } |
912 // This layoutObject is regular column content (i.e. not a spanner). Create
a set if necessary. | 950 // This layoutObject is regular column content (i.e. not a spanner). Create |
| 951 // a set if necessary. |
913 if (objectAfterSubtree) { | 952 if (objectAfterSubtree) { |
914 if (LayoutMultiColumnSpannerPlaceholder* placeholder = | 953 if (LayoutMultiColumnSpannerPlaceholder* placeholder = |
915 objectAfterSubtree->spannerPlaceholder()) { | 954 objectAfterSubtree->spannerPlaceholder()) { |
916 // If inserted right before a spanner, we need to make sure that there's
a set for us there. | 955 // If inserted right before a spanner, we need to make sure that there's |
| 956 // a set for us there. |
917 LayoutBox* previous = placeholder->previousSiblingMultiColumnBox(); | 957 LayoutBox* previous = placeholder->previousSiblingMultiColumnBox(); |
918 if (!previous || !previous->isLayoutMultiColumnSet()) | 958 if (!previous || !previous->isLayoutMultiColumnSet()) |
919 createAndInsertMultiColumnSet(placeholder); | 959 createAndInsertMultiColumnSet(placeholder); |
920 } else { | 960 } else { |
921 // Otherwise, since |objectAfterSubtree| isn't a spanner, it has to mean
that there's | 961 // Otherwise, since |objectAfterSubtree| isn't a spanner, it has to mean |
922 // already a set for that content. We can use it for this layoutObject t
oo. | 962 // that there's already a set for that content. We can use it for this |
| 963 // layoutObject too. |
923 ASSERT(mapDescendantToColumnSet(objectAfterSubtree)); | 964 ASSERT(mapDescendantToColumnSet(objectAfterSubtree)); |
924 ASSERT(mapDescendantToColumnSet(layoutObject) == | 965 ASSERT(mapDescendantToColumnSet(layoutObject) == |
925 mapDescendantToColumnSet(objectAfterSubtree)); | 966 mapDescendantToColumnSet(objectAfterSubtree)); |
926 } | 967 } |
927 } else { | 968 } else { |
928 // Inserting at the end. Then we just need to make sure that there's a col
umn set at the end. | 969 // Inserting at the end. Then we just need to make sure that there's a |
| 970 // column set at the end. |
929 LayoutBox* lastColumnBox = lastMultiColumnBox(); | 971 LayoutBox* lastColumnBox = lastMultiColumnBox(); |
930 if (!lastColumnBox || !lastColumnBox->isLayoutMultiColumnSet()) | 972 if (!lastColumnBox || !lastColumnBox->isLayoutMultiColumnSet()) |
931 createAndInsertMultiColumnSet(); | 973 createAndInsertMultiColumnSet(); |
932 } | 974 } |
933 } | 975 } |
934 } | 976 } |
935 | 977 |
936 void LayoutMultiColumnFlowThread::flowThreadDescendantWillBeRemoved( | 978 void LayoutMultiColumnFlowThread::flowThreadDescendantWillBeRemoved( |
937 LayoutObject* descendant) { | 979 LayoutObject* descendant) { |
938 // This method ensures that the list of column sets and spanner placeholders r
eflects the | 980 // This method ensures that the list of column sets and spanner placeholders |
939 // multicol content that we'll be left with after removal of a descendant (or
descendant | 981 // reflects the multicol content that we'll be left with after removal of a |
940 // subtree). See the header file for more information. Removing content may me
an that we need to | 982 // descendant (or descendant subtree). See the header file for more |
941 // remove column sets and/or spanner placeholders. | 983 // information. Removing content may mean that we need to remove column sets |
| 984 // and/or spanner placeholders. |
942 if (m_isBeingEvacuated) | 985 if (m_isBeingEvacuated) |
943 return; | 986 return; |
944 if (shouldSkipInsertedOrRemovedChild(this, *descendant)) | 987 if (shouldSkipInsertedOrRemovedChild(this, *descendant)) |
945 return; | 988 return; |
946 bool hadContainingPlaceholder = | 989 bool hadContainingPlaceholder = |
947 containingColumnSpannerPlaceholder(descendant); | 990 containingColumnSpannerPlaceholder(descendant); |
948 bool processedSomething = false; | 991 bool processedSomething = false; |
949 LayoutObject* next; | 992 LayoutObject* next; |
950 // Remove spanner placeholders that are no longer needed, and merge column set
s around them. | 993 // Remove spanner placeholders that are no longer needed, and merge column |
| 994 // sets around them. |
951 for (LayoutObject* layoutObject = descendant; layoutObject; | 995 for (LayoutObject* layoutObject = descendant; layoutObject; |
952 layoutObject = next) { | 996 layoutObject = next) { |
953 if (layoutObject != descendant && | 997 if (layoutObject != descendant && |
954 shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { | 998 shouldSkipInsertedOrRemovedChild(this, *layoutObject)) { |
955 next = layoutObject->nextInPreOrderAfterChildren(descendant); | 999 next = layoutObject->nextInPreOrderAfterChildren(descendant); |
956 continue; | 1000 continue; |
957 } | 1001 } |
958 processedSomething = true; | 1002 processedSomething = true; |
959 LayoutMultiColumnSpannerPlaceholder* placeholder = | 1003 LayoutMultiColumnSpannerPlaceholder* placeholder = |
960 layoutObject->spannerPlaceholder(); | 1004 layoutObject->spannerPlaceholder(); |
961 if (!placeholder) { | 1005 if (!placeholder) { |
962 next = layoutObject->nextInPreOrder(descendant); | 1006 next = layoutObject->nextInPreOrder(descendant); |
963 continue; | 1007 continue; |
964 } | 1008 } |
965 next = layoutObject->nextInPreOrderAfterChildren( | 1009 next = layoutObject->nextInPreOrderAfterChildren( |
966 descendant); // It's a spanner. Its children are of no interest to us. | 1010 descendant); // It's a spanner. Its children are of no interest to us. |
967 destroySpannerPlaceholder(placeholder); | 1011 destroySpannerPlaceholder(placeholder); |
968 } | 1012 } |
969 if (hadContainingPlaceholder || !processedSomething) | 1013 if (hadContainingPlaceholder || !processedSomething) |
970 return; // No column content will be removed, so we can stop here. | 1014 return; // No column content will be removed, so we can stop here. |
971 | 1015 |
972 // Column content will be removed. Does this mean that we should destroy a col
umn set? | 1016 // Column content will be removed. Does this mean that we should destroy a |
| 1017 // column set? |
973 LayoutMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = | 1018 LayoutMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = |
974 nullptr; | 1019 nullptr; |
975 LayoutObject* previousLayoutObject = | 1020 LayoutObject* previousLayoutObject = |
976 previousInPreOrderSkippingOutOfFlow(this, descendant); | 1021 previousInPreOrderSkippingOutOfFlow(this, descendant); |
977 if (previousLayoutObject && previousLayoutObject != this) { | 1022 if (previousLayoutObject && previousLayoutObject != this) { |
978 adjacentPreviousSpannerPlaceholder = | 1023 adjacentPreviousSpannerPlaceholder = |
979 containingColumnSpannerPlaceholder(previousLayoutObject); | 1024 containingColumnSpannerPlaceholder(previousLayoutObject); |
980 if (!adjacentPreviousSpannerPlaceholder) | 1025 if (!adjacentPreviousSpannerPlaceholder) |
981 return; // Preceded by column content. Set still needed. | 1026 return; // Preceded by column content. Set still needed. |
982 } | 1027 } |
983 LayoutMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = nullptr; | 1028 LayoutMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = nullptr; |
984 LayoutObject* nextLayoutObject = | 1029 LayoutObject* nextLayoutObject = |
985 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); | 1030 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant); |
986 if (nextLayoutObject) { | 1031 if (nextLayoutObject) { |
987 adjacentNextSpannerPlaceholder = | 1032 adjacentNextSpannerPlaceholder = |
988 containingColumnSpannerPlaceholder(nextLayoutObject); | 1033 containingColumnSpannerPlaceholder(nextLayoutObject); |
989 if (!adjacentNextSpannerPlaceholder) | 1034 if (!adjacentNextSpannerPlaceholder) |
990 return; // Followed by column content. Set still needed. | 1035 return; // Followed by column content. Set still needed. |
991 } | 1036 } |
992 // We have now determined that, with the removal of |descendant|, we should re
move a column | 1037 // We have now determined that, with the removal of |descendant|, we should |
993 // set. Locate it and remove it. Do it without involving mapDescendantToColumn
Set(), as that | 1038 // remove a column set. Locate it and remove it. Do it without involving |
994 // might be very slow. Deduce the right set from the spanner placeholders that
we've already | 1039 // mapDescendantToColumnSet(), as that might be very slow. Deduce the right |
995 // found. | 1040 // set from the spanner placeholders that we've already found. |
996 LayoutMultiColumnSet* columnSetToRemove; | 1041 LayoutMultiColumnSet* columnSetToRemove; |
997 if (adjacentNextSpannerPlaceholder) { | 1042 if (adjacentNextSpannerPlaceholder) { |
998 columnSetToRemove = toLayoutMultiColumnSet( | 1043 columnSetToRemove = toLayoutMultiColumnSet( |
999 adjacentNextSpannerPlaceholder->previousSiblingMultiColumnBox()); | 1044 adjacentNextSpannerPlaceholder->previousSiblingMultiColumnBox()); |
1000 ASSERT(!adjacentPreviousSpannerPlaceholder || | 1045 ASSERT(!adjacentPreviousSpannerPlaceholder || |
1001 columnSetToRemove == | 1046 columnSetToRemove == |
1002 adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox()); | 1047 adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox()); |
1003 } else if (adjacentPreviousSpannerPlaceholder) { | 1048 } else if (adjacentPreviousSpannerPlaceholder) { |
1004 columnSetToRemove = toLayoutMultiColumnSet( | 1049 columnSetToRemove = toLayoutMultiColumnSet( |
1005 adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox()); | 1050 adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox()); |
1006 } else { | 1051 } else { |
1007 // If there were no adjacent spanners, it has to mean that there's only one
column set, | 1052 // If there were no adjacent spanners, it has to mean that there's only one |
1008 // since it's only spanners that may cause creation of multiple sets. | 1053 // column set, since it's only spanners that may cause creation of |
| 1054 // multiple sets. |
1009 columnSetToRemove = firstMultiColumnSet(); | 1055 columnSetToRemove = firstMultiColumnSet(); |
1010 ASSERT(columnSetToRemove); | 1056 ASSERT(columnSetToRemove); |
1011 ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet()); | 1057 ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet()); |
1012 } | 1058 } |
1013 ASSERT(columnSetToRemove); | 1059 ASSERT(columnSetToRemove); |
1014 columnSetToRemove->destroy(); | 1060 columnSetToRemove->destroy(); |
1015 } | 1061 } |
1016 | 1062 |
1017 static inline bool needsToReinsertIntoFlowThread( | 1063 static inline bool needsToReinsertIntoFlowThread( |
1018 const ComputedStyle& oldStyle, | 1064 const ComputedStyle& oldStyle, |
1019 const ComputedStyle& newStyle) { | 1065 const ComputedStyle& newStyle) { |
1020 // If we've become (or are about to become) a container for absolutely positio
ned descendants, | 1066 // If we've become (or are about to become) a container for absolutely |
1021 // or if we're no longer going to be one, we need to re-evaluate the need for
column | 1067 // positioned descendants, or if we're no longer going to be one, we need to |
1022 // sets. There may be out-of-flow descendants further down that become part of
the flow thread, | 1068 // re-evaluate the need for column sets. There may be out-of-flow descendants |
1023 // or cease to be part of the flow thread, because of this change. | 1069 // further down that become part of the flow thread, or cease to be part of |
| 1070 // the flow thread, because of this change. |
1024 if (oldStyle.hasTransformRelatedProperty() != | 1071 if (oldStyle.hasTransformRelatedProperty() != |
1025 newStyle.hasTransformRelatedProperty()) | 1072 newStyle.hasTransformRelatedProperty()) |
1026 return true; | 1073 return true; |
1027 return (oldStyle.hasInFlowPosition() && | 1074 return (oldStyle.hasInFlowPosition() && |
1028 newStyle.position() == StaticPosition) || | 1075 newStyle.position() == StaticPosition) || |
1029 (newStyle.hasInFlowPosition() && | 1076 (newStyle.hasInFlowPosition() && |
1030 oldStyle.position() == StaticPosition); | 1077 oldStyle.position() == StaticPosition); |
1031 } | 1078 } |
1032 | 1079 |
1033 static inline bool needsToRemoveFromFlowThread(const ComputedStyle& oldStyle, | 1080 static inline bool needsToRemoveFromFlowThread(const ComputedStyle& oldStyle, |
1034 const ComputedStyle& newStyle) { | 1081 const ComputedStyle& newStyle) { |
1035 // If an in-flow descendant goes out-of-flow, we may have to remove column set
s and spanner placeholders. | 1082 // If an in-flow descendant goes out-of-flow, we may have to remove column |
| 1083 // sets and spanner placeholders. |
1036 return (newStyle.hasOutOfFlowPosition() && | 1084 return (newStyle.hasOutOfFlowPosition() && |
1037 !oldStyle.hasOutOfFlowPosition()) || | 1085 !oldStyle.hasOutOfFlowPosition()) || |
1038 needsToReinsertIntoFlowThread(oldStyle, newStyle); | 1086 needsToReinsertIntoFlowThread(oldStyle, newStyle); |
1039 } | 1087 } |
1040 | 1088 |
1041 static inline bool needsToInsertIntoFlowThread(const ComputedStyle& oldStyle, | 1089 static inline bool needsToInsertIntoFlowThread(const ComputedStyle& oldStyle, |
1042 const ComputedStyle& newStyle) { | 1090 const ComputedStyle& newStyle) { |
1043 // If an out-of-flow descendant goes in-flow, we may have to insert column set
s and spanner placeholders. | 1091 // If an out-of-flow descendant goes in-flow, we may have to insert column |
| 1092 // sets and spanner placeholders. |
1044 return (!newStyle.hasOutOfFlowPosition() && | 1093 return (!newStyle.hasOutOfFlowPosition() && |
1045 oldStyle.hasOutOfFlowPosition()) || | 1094 oldStyle.hasOutOfFlowPosition()) || |
1046 needsToReinsertIntoFlowThread(oldStyle, newStyle); | 1095 needsToReinsertIntoFlowThread(oldStyle, newStyle); |
1047 } | 1096 } |
1048 | 1097 |
1049 void LayoutMultiColumnFlowThread::flowThreadDescendantStyleWillChange( | 1098 void LayoutMultiColumnFlowThread::flowThreadDescendantStyleWillChange( |
1050 LayoutBox* descendant, | 1099 LayoutBox* descendant, |
1051 StyleDifference diff, | 1100 StyleDifference diff, |
1052 const ComputedStyle& newStyle) { | 1101 const ComputedStyle& newStyle) { |
1053 if (needsToRemoveFromFlowThread(descendant->styleRef(), newStyle)) | 1102 if (needsToRemoveFromFlowThread(descendant->styleRef(), newStyle)) |
1054 flowThreadDescendantWillBeRemoved(descendant); | 1103 flowThreadDescendantWillBeRemoved(descendant); |
1055 } | 1104 } |
1056 | 1105 |
1057 void LayoutMultiColumnFlowThread::flowThreadDescendantStyleDidChange( | 1106 void LayoutMultiColumnFlowThread::flowThreadDescendantStyleDidChange( |
1058 LayoutBox* descendant, | 1107 LayoutBox* descendant, |
1059 StyleDifference diff, | 1108 StyleDifference diff, |
1060 const ComputedStyle& oldStyle) { | 1109 const ComputedStyle& oldStyle) { |
1061 if (needsToInsertIntoFlowThread(oldStyle, descendant->styleRef())) { | 1110 if (needsToInsertIntoFlowThread(oldStyle, descendant->styleRef())) { |
1062 flowThreadDescendantWasInserted(descendant); | 1111 flowThreadDescendantWasInserted(descendant); |
1063 return; | 1112 return; |
1064 } | 1113 } |
1065 if (descendantIsValidColumnSpanner(descendant)) { | 1114 if (descendantIsValidColumnSpanner(descendant)) { |
1066 // We went from being regular column content to becoming a spanner. | 1115 // We went from being regular column content to becoming a spanner. |
1067 ASSERT(!descendant->spannerPlaceholder()); | 1116 ASSERT(!descendant->spannerPlaceholder()); |
1068 | 1117 |
1069 // First remove this as regular column content. Note that this will walk the
entire subtree | 1118 // First remove this as regular column content. Note that this will walk the |
1070 // of |descendant|. There might be spanners there (which won't be spanners a
nymore, since | 1119 // entire subtree of |descendant|. There might be spanners there (which |
1071 // we're not allowed to nest spanners), whose placeholders must die. | 1120 // won't be spanners anymore, since we're not allowed to nest spanners), |
| 1121 // whose placeholders must die. |
1072 flowThreadDescendantWillBeRemoved(descendant); | 1122 flowThreadDescendantWillBeRemoved(descendant); |
1073 | 1123 |
1074 createAndInsertSpannerPlaceholder( | 1124 createAndInsertSpannerPlaceholder( |
1075 descendant, | 1125 descendant, |
1076 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant)); | 1126 nextInPreOrderAfterChildrenSkippingOutOfFlow(this, descendant)); |
1077 } | 1127 } |
1078 } | 1128 } |
1079 | 1129 |
1080 void LayoutMultiColumnFlowThread::computePreferredLogicalWidths() { | 1130 void LayoutMultiColumnFlowThread::computePreferredLogicalWidths() { |
1081 LayoutFlowThread::computePreferredLogicalWidths(); | 1131 LayoutFlowThread::computePreferredLogicalWidths(); |
1082 | 1132 |
1083 // The min/max intrinsic widths calculated really tell how much space elements
need when | 1133 // The min/max intrinsic widths calculated really tell how much space elements |
1084 // laid out inside the columns. In order to eventually end up with the desired
column width, | 1134 // need when laid out inside the columns. In order to eventually end up with |
1085 // we need to convert them to values pertaining to the multicol container. | 1135 // the desired column width, we need to convert them to values pertaining to |
| 1136 // the multicol container. |
1086 const LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); | 1137 const LayoutBlockFlow* multicolContainer = multiColumnBlockFlow(); |
1087 const ComputedStyle* multicolStyle = multicolContainer->style(); | 1138 const ComputedStyle* multicolStyle = multicolContainer->style(); |
1088 int columnCount = | 1139 int columnCount = |
1089 multicolStyle->hasAutoColumnCount() ? 1 : multicolStyle->columnCount(); | 1140 multicolStyle->hasAutoColumnCount() ? 1 : multicolStyle->columnCount(); |
1090 LayoutUnit columnWidth; | 1141 LayoutUnit columnWidth; |
1091 LayoutUnit gapExtra = | 1142 LayoutUnit gapExtra = |
1092 LayoutUnit((columnCount - 1) * multicolContainer->columnGap()); | 1143 LayoutUnit((columnCount - 1) * multicolContainer->columnGap()); |
1093 if (multicolStyle->hasAutoColumnWidth()) { | 1144 if (multicolStyle->hasAutoColumnWidth()) { |
1094 m_minPreferredLogicalWidth = | 1145 m_minPreferredLogicalWidth = |
1095 m_minPreferredLogicalWidth * columnCount + gapExtra; | 1146 m_minPreferredLogicalWidth * columnCount + gapExtra; |
1096 } else { | 1147 } else { |
1097 columnWidth = LayoutUnit(multicolStyle->columnWidth()); | 1148 columnWidth = LayoutUnit(multicolStyle->columnWidth()); |
1098 m_minPreferredLogicalWidth = | 1149 m_minPreferredLogicalWidth = |
1099 std::min(m_minPreferredLogicalWidth, columnWidth); | 1150 std::min(m_minPreferredLogicalWidth, columnWidth); |
1100 } | 1151 } |
1101 // Note that if column-count is auto here, we should resolve it to calculate t
he maximum | 1152 // Note that if column-count is auto here, we should resolve it to calculate |
1102 // intrinsic width, instead of pretending that it's 1. The only way to do that
is by performing | 1153 // the maximum intrinsic width, instead of pretending that it's 1. The only |
1103 // a layout pass, but this is not an appropriate time or place for layout. The
good news is that | 1154 // way to do that is by performing a layout pass, but this is not an |
1104 // if height is unconstrained and there are no explicit breaks, the resolved c
olumn-count really | 1155 // appropriate time or place for layout. The good news is that if height is |
1105 // should be 1. | 1156 // unconstrained and there are no explicit breaks, the resolved column-count |
| 1157 // really should be 1. |
1106 m_maxPreferredLogicalWidth = | 1158 m_maxPreferredLogicalWidth = |
1107 std::max(m_maxPreferredLogicalWidth, columnWidth) * columnCount + | 1159 std::max(m_maxPreferredLogicalWidth, columnWidth) * columnCount + |
1108 gapExtra; | 1160 gapExtra; |
1109 } | 1161 } |
1110 | 1162 |
1111 void LayoutMultiColumnFlowThread::computeLogicalHeight( | 1163 void LayoutMultiColumnFlowThread::computeLogicalHeight( |
1112 LayoutUnit logicalHeight, | 1164 LayoutUnit logicalHeight, |
1113 LayoutUnit logicalTop, | 1165 LayoutUnit logicalTop, |
1114 LogicalExtentComputedValues& computedValues) const { | 1166 LogicalExtentComputedValues& computedValues) const { |
1115 // We simply remain at our intrinsic height. | 1167 // We simply remain at our intrinsic height. |
1116 computedValues.m_extent = logicalHeight; | 1168 computedValues.m_extent = logicalHeight; |
1117 computedValues.m_position = logicalTop; | 1169 computedValues.m_position = logicalTop; |
1118 } | 1170 } |
1119 | 1171 |
1120 void LayoutMultiColumnFlowThread::updateLogicalWidth() { | 1172 void LayoutMultiColumnFlowThread::updateLogicalWidth() { |
1121 LayoutUnit columnWidth; | 1173 LayoutUnit columnWidth; |
1122 calculateColumnCountAndWidth(columnWidth, m_columnCount); | 1174 calculateColumnCountAndWidth(columnWidth, m_columnCount); |
1123 setLogicalWidth(columnWidth); | 1175 setLogicalWidth(columnWidth); |
1124 } | 1176 } |
1125 | 1177 |
1126 void LayoutMultiColumnFlowThread::layout() { | 1178 void LayoutMultiColumnFlowThread::layout() { |
1127 ASSERT(!m_lastSetWorkedOn); | 1179 ASSERT(!m_lastSetWorkedOn); |
1128 m_lastSetWorkedOn = firstMultiColumnSet(); | 1180 m_lastSetWorkedOn = firstMultiColumnSet(); |
1129 if (m_lastSetWorkedOn) | 1181 if (m_lastSetWorkedOn) |
1130 m_lastSetWorkedOn->beginFlow(LayoutUnit()); | 1182 m_lastSetWorkedOn->beginFlow(LayoutUnit()); |
1131 LayoutFlowThread::layout(); | 1183 LayoutFlowThread::layout(); |
1132 if (LayoutMultiColumnSet* lastSet = lastMultiColumnSet()) { | 1184 if (LayoutMultiColumnSet* lastSet = lastMultiColumnSet()) { |
1133 ASSERT(lastSet == m_lastSetWorkedOn); | 1185 ASSERT(lastSet == m_lastSetWorkedOn); |
1134 if (!lastSet->nextSiblingMultiColumnBox()) { | 1186 if (!lastSet->nextSiblingMultiColumnBox()) { |
1135 // Include trailing overflow in the last column set. The idea is that we w
ill generate | 1187 // Include trailing overflow in the last column set. The idea is that we |
1136 // additional columns and pages to hold that overflow, since people do wri
te bad content | 1188 // will generate additional columns and pages to hold that overflow, since |
1137 // like <body style="height:0px"> in multi-column layouts. | 1189 // people do write bad content like <body style="height:0px"> in |
1138 // TODO(mstensho): Once we support nested multicol, adding in overflow her
e may result | 1190 // multi-column layouts. |
1139 // in the need for creating additional rows, since there may not be enough
space | 1191 // TODO(mstensho): Once we support nested multicol, adding in overflow |
1140 // remaining in the currently last row. | 1192 // here may result in the need for creating additional rows, since there |
| 1193 // may not be enough space remaining in the currently last row. |
1141 LayoutRect layoutRect = layoutOverflowRect(); | 1194 LayoutRect layoutRect = layoutOverflowRect(); |
1142 LayoutUnit logicalBottomInFlowThread = | 1195 LayoutUnit logicalBottomInFlowThread = |
1143 isHorizontalWritingMode() ? layoutRect.maxY() : layoutRect.maxX(); | 1196 isHorizontalWritingMode() ? layoutRect.maxY() : layoutRect.maxX(); |
1144 ASSERT(logicalBottomInFlowThread >= logicalHeight()); | 1197 ASSERT(logicalBottomInFlowThread >= logicalHeight()); |
1145 lastSet->endFlow(logicalBottomInFlowThread); | 1198 lastSet->endFlow(logicalBottomInFlowThread); |
1146 } | 1199 } |
1147 } | 1200 } |
1148 m_lastSetWorkedOn = nullptr; | 1201 m_lastSetWorkedOn = nullptr; |
1149 } | 1202 } |
1150 | 1203 |
1151 void LayoutMultiColumnFlowThread::contentWasLaidOut( | 1204 void LayoutMultiColumnFlowThread::contentWasLaidOut( |
1152 LayoutUnit logicalBottomInFlowThreadAfterPagination) { | 1205 LayoutUnit logicalBottomInFlowThreadAfterPagination) { |
1153 // Check if we need another fragmentainer group. If we've run out of columns i
n the last | 1206 // Check if we need another fragmentainer group. If we've run out of columns |
1154 // fragmentainer group (column row), we need to insert another fragmentainer g
roup to hold more | 1207 // in the last fragmentainer group (column row), we need to insert another |
1155 // columns. | 1208 // fragmentainer group to hold more columns. |
1156 | 1209 |
1157 // First figure out if there's any chance that we're nested at all. If we can
be sure that | 1210 // First figure out if there's any chance that we're nested at all. If we can |
1158 // we're not, bail early. This code is run very often, and since locating a co
ntaining flow | 1211 // be sure that we're not, bail early. This code is run very often, and since |
1159 // thread has some cost (depending on tree depth), avoid calling | 1212 // locating a containing flow thread has some cost (depending on tree depth), |
1160 // enclosingFragmentationContext() right away. This test may give some false p
ositives (hence | 1213 // avoid calling enclosingFragmentationContext() right away. This test may |
1161 // the "mayBe"), if we're in an out-of-flow subtree and have an outer multicol
container that | 1214 // give some false positives (hence the "mayBe"), if we're in an out-of-flow |
1162 // doesn't affect us, but that's okay. We'll discover that further down the ro
ad when trying to | 1215 // subtree and have an outer multicol container that doesn't affect us, but |
| 1216 // that's okay. We'll discover that further down the road when trying to |
1163 // locate our enclosing flow thread for real. | 1217 // locate our enclosing flow thread for real. |
1164 bool mayBeNested = multiColumnBlockFlow()->isInsideFlowThread() || | 1218 bool mayBeNested = multiColumnBlockFlow()->isInsideFlowThread() || |
1165 view()->fragmentationContext(); | 1219 view()->fragmentationContext(); |
1166 if (!mayBeNested) | 1220 if (!mayBeNested) |
1167 return; | 1221 return; |
1168 appendNewFragmentainerGroupIfNeeded(logicalBottomInFlowThreadAfterPagination, | 1222 appendNewFragmentainerGroupIfNeeded(logicalBottomInFlowThreadAfterPagination, |
1169 AssociateWithFormerPage); | 1223 AssociateWithFormerPage); |
1170 } | 1224 } |
1171 | 1225 |
1172 bool LayoutMultiColumnFlowThread::canSkipLayout(const LayoutBox& root) const { | 1226 bool LayoutMultiColumnFlowThread::canSkipLayout(const LayoutBox& root) const { |
1173 // Objects containing spanners is all we need to worry about, so if there are
no spanners at all | 1227 // Objects containing spanners is all we need to worry about, so if there are |
1174 // in this multicol container, we can just return the good news right away. | 1228 // no spanners at all in this multicol container, we can just return the good |
| 1229 // news right away. |
1175 if (!hasAnyColumnSpanners(*this)) | 1230 if (!hasAnyColumnSpanners(*this)) |
1176 return true; | 1231 return true; |
1177 | 1232 |
1178 LayoutObject* next; | 1233 LayoutObject* next; |
1179 for (const LayoutObject* object = &root; object; object = next) { | 1234 for (const LayoutObject* object = &root; object; object = next) { |
1180 if (object->isColumnSpanAll()) { | 1235 if (object->isColumnSpanAll()) { |
1181 // A spanner potentially ends one fragmentainer group and begins a new one
, and thus | 1236 // A spanner potentially ends one fragmentainer group and begins a new |
1182 // determines the flow thread portion bottom and top of adjacent fragmenta
iner | 1237 // one, and thus determines the flow thread portion bottom and top of |
1183 // groups. It's just too hard to guess these values without laying out. | 1238 // adjacent fragmentainer groups. It's just too hard to guess these values |
| 1239 // without laying out. |
1184 return false; | 1240 return false; |
1185 } | 1241 } |
1186 if (canContainSpannerInParentFragmentationContext(*object)) | 1242 if (canContainSpannerInParentFragmentationContext(*object)) |
1187 next = object->nextInPreOrder(&root); | 1243 next = object->nextInPreOrder(&root); |
1188 else | 1244 else |
1189 next = object->nextInPreOrderAfterChildren(&root); | 1245 next = object->nextInPreOrderAfterChildren(&root); |
1190 } | 1246 } |
1191 return true; | 1247 return true; |
1192 } | 1248 } |
1193 | 1249 |
1194 MultiColumnLayoutState LayoutMultiColumnFlowThread::multiColumnLayoutState() | 1250 MultiColumnLayoutState LayoutMultiColumnFlowThread::multiColumnLayoutState() |
1195 const { | 1251 const { |
1196 return MultiColumnLayoutState(m_lastSetWorkedOn); | 1252 return MultiColumnLayoutState(m_lastSetWorkedOn); |
1197 } | 1253 } |
1198 | 1254 |
1199 void LayoutMultiColumnFlowThread::restoreMultiColumnLayoutState( | 1255 void LayoutMultiColumnFlowThread::restoreMultiColumnLayoutState( |
1200 const MultiColumnLayoutState& state) { | 1256 const MultiColumnLayoutState& state) { |
1201 m_lastSetWorkedOn = state.columnSet(); | 1257 m_lastSetWorkedOn = state.columnSet(); |
1202 } | 1258 } |
1203 | 1259 |
1204 } // namespace blink | 1260 } // namespace blink |
OLD | NEW |