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 |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/rendering/RenderMultiColumnFlowThread.h" | 27 #include "core/rendering/RenderMultiColumnFlowThread.h" |
28 | 28 |
29 #include "core/rendering/RenderMultiColumnSet.h" | 29 #include "core/rendering/RenderMultiColumnSet.h" |
30 #include "core/rendering/RenderMultiColumnSpannerPlaceholder.h" | 30 #include "core/rendering/RenderMultiColumnSpannerPlaceholder.h" |
31 | 31 |
32 namespace blink { | 32 namespace blink { |
33 | 33 |
34 RenderMultiColumnFlowThread::RenderMultiColumnFlowThread() | 34 RenderMultiColumnFlowThread::RenderMultiColumnFlowThread() |
35 : m_columnCount(1) | 35 : m_lastSetWorkedOn(0) |
| 36 , m_columnCount(1) |
36 , m_columnHeightAvailable(0) | 37 , m_columnHeightAvailable(0) |
37 , m_inBalancingPass(false) | 38 , m_inBalancingPass(false) |
38 , m_needsColumnHeightsRecalculation(false) | 39 , m_needsColumnHeightsRecalculation(false) |
39 , m_progressionIsInline(true) | 40 , m_progressionIsInline(true) |
40 , m_isBeingEvacuated(false) | 41 , m_isBeingEvacuated(false) |
41 { | 42 { |
42 setFlowThreadState(InsideInFlowThread); | 43 setFlowThreadState(InsideInFlowThread); |
43 } | 44 } |
44 | 45 |
45 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() | 46 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 } | 144 } |
144 | 145 |
145 bool RenderMultiColumnFlowThread::needsNewWidth() const | 146 bool RenderMultiColumnFlowThread::needsNewWidth() const |
146 { | 147 { |
147 LayoutUnit newWidth; | 148 LayoutUnit newWidth; |
148 unsigned dummyColumnCount; // We only care if used column-width changes. | 149 unsigned dummyColumnCount; // We only care if used column-width changes. |
149 calculateColumnCountAndWidth(newWidth, dummyColumnCount); | 150 calculateColumnCountAndWidth(newWidth, dummyColumnCount); |
150 return newWidth != logicalWidth(); | 151 return newWidth != logicalWidth(); |
151 } | 152 } |
152 | 153 |
| 154 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout
Unit offset) const |
| 155 { |
| 156 if (m_lastSetWorkedOn) { |
| 157 // Layout in progress. We are calculating the set heights as we speak, s
o the column set range |
| 158 // information is not up-to-date. |
| 159 return m_lastSetWorkedOn; |
| 160 } |
| 161 |
| 162 ASSERT(!m_regionsInvalidated); |
| 163 if (m_multiColumnSetList.isEmpty()) |
| 164 return 0; |
| 165 if (offset <= 0) |
| 166 return m_multiColumnSetList.first(); |
| 167 |
| 168 MultiColumnSetSearchAdapter adapter(offset); |
| 169 m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdap
ter>(adapter); |
| 170 |
| 171 // If no set was found, the offset is in the flow thread overflow. |
| 172 if (!adapter.result() && !m_multiColumnSetList.isEmpty()) |
| 173 return m_multiColumnSetList.last(); |
| 174 return adapter.result(); |
| 175 } |
| 176 |
153 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
youtScope& layoutScope) | 177 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
youtScope& layoutScope) |
154 { | 178 { |
155 if (relayoutChildren) | 179 if (relayoutChildren) |
156 layoutScope.setChildNeedsLayout(this); | 180 layoutScope.setChildNeedsLayout(this); |
157 | 181 |
| 182 m_needsColumnHeightsRecalculation = false; |
158 if (!needsLayout()) { | 183 if (!needsLayout()) { |
159 // Just before the multicol container (our parent RenderBlockFlow) finis
hes laying out, it | 184 // Just before the multicol container (our parent RenderBlockFlow) finis
hes laying out, it |
160 // will call recalculateColumnHeights() on us unconditionally, but we on
ly want that method | 185 // will call recalculateColumnHeights() on us unconditionally, but we on
ly want that method |
161 // to do any work if we actually laid out the flow thread. Otherwise, th
e balancing | 186 // to do any work if we actually laid out the flow thread. Otherwise, th
e balancing |
162 // machinery would kick in needlessly, and trigger additional layout pas
ses. Furthermore, we | 187 // machinery would kick in needlessly, and trigger additional layout pas
ses. Furthermore, we |
163 // actually depend on a proper flowthread layout pass in order to do bal
ancing, since it's | 188 // actually depend on a proper flowthread layout pass in order to do bal
ancing, since it's |
164 // flowthread layout that sets up content runs. | 189 // flowthread layout that sets up content runs. |
165 m_needsColumnHeightsRecalculation = false; | |
166 return; | 190 return; |
167 } | 191 } |
168 | 192 |
169 for (RenderBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co
lumnBox->nextSiblingBox()) { | 193 for (RenderBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co
lumnBox->nextSiblingMultiColumnBox()) { |
170 if (!columnBox->isRenderMultiColumnSet()) { | 194 if (!columnBox->isRenderMultiColumnSet()) { |
171 ASSERT(columnBox->isRenderMultiColumnSpannerPlaceholder()); // no ot
her type is expected. | 195 ASSERT(columnBox->isRenderMultiColumnSpannerPlaceholder()); // no ot
her type is expected. |
| 196 m_needsColumnHeightsRecalculation = true; |
172 continue; | 197 continue; |
173 } | 198 } |
174 RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(columnBox); | 199 RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(columnBox); |
175 if (!m_inBalancingPass) { | 200 if (!m_inBalancingPass) { |
176 // This is the initial layout pass. We need to reset the column heig
ht, because contents | 201 // This is the initial layout pass. We need to reset the column heig
ht, because contents |
177 // typically have changed. | 202 // typically have changed. |
178 columnSet->resetColumnHeight(); | 203 columnSet->resetColumnHeight(); |
179 } | 204 } |
| 205 if (!m_needsColumnHeightsRecalculation) |
| 206 m_needsColumnHeightsRecalculation = columnSet->heightIsAuto(); |
180 } | 207 } |
181 | 208 |
182 invalidateRegions(); | 209 invalidateRegions(); |
183 m_needsColumnHeightsRecalculation = heightIsAuto(); | |
184 layout(); | 210 layout(); |
185 } | 211 } |
186 | 212 |
187 bool RenderMultiColumnFlowThread::recalculateColumnHeights() | 213 bool RenderMultiColumnFlowThread::recalculateColumnHeights() |
188 { | 214 { |
189 // All column sets that needed layout have now been laid out, so we can fina
lly validate them. | 215 // All column sets that needed layout have now been laid out, so we can fina
lly validate them. |
190 validateRegions(); | 216 validateRegions(); |
191 | 217 |
192 if (!m_needsColumnHeightsRecalculation) | 218 if (!m_needsColumnHeightsRecalculation) |
193 return false; | 219 return false; |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 { | 346 { |
321 // Detach all column sets from the flow thread. Cannot destroy them at this
point, since they | 347 // Detach all column sets from the flow thread. Cannot destroy them at this
point, since they |
322 // are siblings of this object, and there may be pointers to this object's s
ibling somewhere | 348 // are siblings of this object, and there may be pointers to this object's s
ibling somewhere |
323 // further up on the call stack. | 349 // further up on the call stack. |
324 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col
umnSet = columnSet->nextSiblingMultiColumnSet()) | 350 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col
umnSet = columnSet->nextSiblingMultiColumnSet()) |
325 columnSet->detachRegion(); | 351 columnSet->detachRegion(); |
326 multiColumnBlockFlow()->resetMultiColumnFlowThread(); | 352 multiColumnBlockFlow()->resetMultiColumnFlowThread(); |
327 RenderFlowThread::willBeRemovedFromTree(); | 353 RenderFlowThread::willBeRemovedFromTree(); |
328 } | 354 } |
329 | 355 |
| 356 LayoutUnit RenderMultiColumnFlowThread::skipColumnSpanner(RenderBox* renderer, L
ayoutUnit logicalTopInFlowThread) |
| 357 { |
| 358 ASSERT(renderer->isColumnSpanAll()); |
| 359 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlacehol
der(); |
| 360 LayoutUnit adjustment; |
| 361 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); |
| 362 if (previousColumnBox && previousColumnBox->isRenderMultiColumnSet()) { |
| 363 // Pad flow thread offset to a column boundary, so that any column conte
nt that's supposed |
| 364 // to come after the spanner doesn't bleed into the column row preceding
the spanner. |
| 365 RenderMultiColumnSet* previousSet = toRenderMultiColumnSet(previousColum
nBox); |
| 366 if (previousSet->pageLogicalHeight()) { |
| 367 LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTo
pForOffset(logicalTopInFlowThread); |
| 368 if (columnLogicalTopInFlowThread != logicalTopInFlowThread) { |
| 369 adjustment = columnLogicalTopInFlowThread + previousSet->pageLog
icalHeight() - logicalTopInFlowThread; |
| 370 logicalTopInFlowThread += adjustment; |
| 371 } |
| 372 } |
| 373 previousSet->endFlow(logicalTopInFlowThread); |
| 374 } |
| 375 RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox(); |
| 376 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet()) { |
| 377 RenderMultiColumnSet* nextSet = toRenderMultiColumnSet(nextColumnBox); |
| 378 m_lastSetWorkedOn = nextSet; |
| 379 nextSet->beginFlow(logicalTopInFlowThread); |
| 380 } |
| 381 return adjustment; |
| 382 } |
| 383 |
330 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject*
descendant) | 384 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject*
descendant) |
331 { | 385 { |
332 ASSERT(!m_isBeingEvacuated); | 386 ASSERT(!m_isBeingEvacuated); |
333 // Go through the subtree that was just inserted and create column sets (nee
ded by regular | 387 // Go through the subtree that was just inserted and create column sets (nee
ded by regular |
334 // column content) and spanner placeholders (one needed by each spanner). | 388 // column content) and spanner placeholders (one needed by each spanner). |
335 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex
tInPreOrder(descendant)) { | 389 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex
tInPreOrder(descendant)) { |
336 if (containingColumnSpannerPlaceholder(renderer)) | 390 if (containingColumnSpannerPlaceholder(renderer)) |
337 continue; // Inside a column spanner. Nothing to do, then. | 391 continue; // Inside a column spanner. Nothing to do, then. |
338 if (descendantIsValidColumnSpanner(renderer)) { | 392 if (descendantIsValidColumnSpanner(renderer)) { |
339 // This renderer is a spanner, so it needs to establish a spanner pl
aceholder. | 393 // This renderer is a spanner, so it needs to establish a spanner pl
aceholder. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 | 437 |
384 void RenderMultiColumnFlowThread::updateLogicalWidth() | 438 void RenderMultiColumnFlowThread::updateLogicalWidth() |
385 { | 439 { |
386 LayoutUnit columnWidth; | 440 LayoutUnit columnWidth; |
387 calculateColumnCountAndWidth(columnWidth, m_columnCount); | 441 calculateColumnCountAndWidth(columnWidth, m_columnCount); |
388 setLogicalWidth(columnWidth); | 442 setLogicalWidth(columnWidth); |
389 } | 443 } |
390 | 444 |
391 void RenderMultiColumnFlowThread::layout() | 445 void RenderMultiColumnFlowThread::layout() |
392 { | 446 { |
| 447 ASSERT(!m_lastSetWorkedOn); |
| 448 m_lastSetWorkedOn = firstMultiColumnSet(); |
| 449 if (m_lastSetWorkedOn) |
| 450 m_lastSetWorkedOn->beginFlow(LayoutUnit()); |
393 RenderFlowThread::layout(); | 451 RenderFlowThread::layout(); |
394 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { | 452 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { |
395 if (!lastSet->nextSiblingMultiColumnBox()) | 453 ASSERT(lastSet == m_lastSetWorkedOn); |
| 454 if (!lastSet->nextSiblingMultiColumnBox()) { |
| 455 lastSet->endFlow(logicalHeight()); |
396 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); | 456 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); |
| 457 } |
397 } | 458 } |
| 459 m_lastSetWorkedOn = 0; |
398 } | 460 } |
399 | 461 |
400 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa
ceShortage) | 462 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa
ceShortage) |
401 { | 463 { |
402 // Only positive values are interesting (and allowed) here. Zero space short
age may be reported | 464 // Only positive values are interesting (and allowed) here. Zero space short
age may be reported |
403 // when we're at the top of a column and the element has zero height. Ignore
this, and also | 465 // when we're at the top of a column and the element has zero height. Ignore
this, and also |
404 // ignore any negative values, which may occur when we set an early break in
order to honor | 466 // ignore any negative values, which may occur when we set an early break in
order to honor |
405 // widows in the next column. | 467 // widows in the next column. |
406 if (spaceShortage <= 0) | 468 if (spaceShortage <= 0) |
407 return; | 469 return; |
408 | 470 |
409 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 471 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
410 multicolSet->recordSpaceShortage(spaceShortage); | 472 multicolSet->recordSpaceShortage(spaceShortage); |
411 } | 473 } |
412 | 474 |
413 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay
outUnit minHeight) | 475 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay
outUnit minHeight) |
414 { | 476 { |
415 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 477 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
416 multicolSet->updateMinimumColumnHeight(minHeight); | 478 multicolSet->updateMinimumColumnHeight(minHeight); |
417 } | 479 } |
418 | 480 |
419 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout
Unit /*offset*/) const | |
420 { | |
421 // For now there's only one column set, so this is easy: | |
422 return firstMultiColumnSet(); | |
423 } | |
424 | |
425 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render
Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) | 481 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render
Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) |
426 { | 482 { |
427 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { | 483 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { |
428 multicolSet->addContentRun(offset); | 484 multicolSet->addContentRun(offset); |
429 if (offsetBreakAdjustment) | 485 if (offsetBreakAdjustment) |
430 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe
mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); | 486 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe
mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); |
431 return true; | 487 return true; |
432 } | 488 } |
433 return false; | 489 return false; |
434 } | 490 } |
435 | 491 |
436 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 492 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
437 { | 493 { |
438 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) | 494 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
439 return columnSet->pageLogicalHeight(); | 495 return columnSet->pageLogicalHeight(); |
440 return false; | 496 return false; |
441 } | 497 } |
442 | 498 |
443 } | 499 } |
OLD | NEW |