Chromium Code Reviews| 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 (offset <= 0) | |
| 164 return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first() ; | |
|
Julien - ping for review
2015/01/19 10:05:11
FWIW if we have no column set (m_multiColumnSetLis
mstensho (USE GERRIT)
2015/01/19 12:02:55
Done.
| |
| 165 | |
| 166 MultiColumnSetSearchAdapter adapter(offset); | |
| 167 m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdap ter>(adapter); | |
| 168 | |
| 169 // If no set was found, the offset is in the flow thread overflow. | |
| 170 if (!adapter.result() && !m_multiColumnSetList.isEmpty()) | |
| 171 return m_multiColumnSetList.last(); | |
| 172 return adapter.result(); | |
| 173 } | |
| 174 | |
| 153 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa youtScope& layoutScope) | 175 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa youtScope& layoutScope) |
| 154 { | 176 { |
| 155 if (relayoutChildren) | 177 if (relayoutChildren) |
| 156 layoutScope.setChildNeedsLayout(this); | 178 layoutScope.setChildNeedsLayout(this); |
| 157 | 179 |
| 180 m_needsColumnHeightsRecalculation = false; | |
| 158 if (!needsLayout()) { | 181 if (!needsLayout()) { |
| 159 // Just before the multicol container (our parent RenderBlockFlow) finis hes laying out, it | 182 // 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 | 183 // 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 | 184 // 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 | 185 // 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 | 186 // 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. | 187 // flowthread layout that sets up content runs. |
| 165 m_needsColumnHeightsRecalculation = false; | |
| 166 return; | 188 return; |
| 167 } | 189 } |
| 168 | 190 |
| 169 for (RenderBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co lumnBox->nextSiblingBox()) { | 191 for (RenderBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co lumnBox->nextSiblingMultiColumnBox()) { |
| 170 if (!columnBox->isRenderMultiColumnSet()) { | 192 if (!columnBox->isRenderMultiColumnSet()) { |
| 171 ASSERT(columnBox->isRenderMultiColumnSpannerPlaceholder()); // no ot her type is expected. | 193 ASSERT(columnBox->isRenderMultiColumnSpannerPlaceholder()); // no ot her type is expected. |
| 194 m_needsColumnHeightsRecalculation = true; | |
| 172 continue; | 195 continue; |
| 173 } | 196 } |
| 174 RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(columnBox); | 197 RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(columnBox); |
| 175 if (!m_inBalancingPass) { | 198 if (!m_inBalancingPass) { |
| 176 // This is the initial layout pass. We need to reset the column heig ht, because contents | 199 // This is the initial layout pass. We need to reset the column heig ht, because contents |
| 177 // typically have changed. | 200 // typically have changed. |
| 178 columnSet->resetColumnHeight(); | 201 columnSet->resetColumnHeight(); |
| 179 } | 202 } |
| 203 if (!m_needsColumnHeightsRecalculation) | |
| 204 m_needsColumnHeightsRecalculation = columnSet->heightIsAuto(); | |
|
Julien - ping for review
2015/01/19 10:05:11
We could avoid the branch with:
m_needsColumnHeig
mstensho (USE GERRIT)
2015/01/19 12:02:55
Then you'd end up calling heightIsAuto() even if m
| |
| 180 } | 205 } |
| 181 | 206 |
| 182 invalidateRegions(); | 207 invalidateRegions(); |
| 183 m_needsColumnHeightsRecalculation = heightIsAuto(); | |
| 184 layout(); | 208 layout(); |
| 185 } | 209 } |
| 186 | 210 |
| 187 bool RenderMultiColumnFlowThread::recalculateColumnHeights() | 211 bool RenderMultiColumnFlowThread::recalculateColumnHeights() |
| 188 { | 212 { |
| 189 // All column sets that needed layout have now been laid out, so we can fina lly validate them. | 213 // All column sets that needed layout have now been laid out, so we can fina lly validate them. |
| 190 validateRegions(); | 214 validateRegions(); |
| 191 | 215 |
| 192 if (!m_needsColumnHeightsRecalculation) | 216 if (!m_needsColumnHeightsRecalculation) |
| 193 return false; | 217 return false; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 { | 344 { |
| 321 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they | 345 // 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 | 346 // are siblings of this object, and there may be pointers to this object's s ibling somewhere |
| 323 // further up on the call stack. | 347 // further up on the call stack. |
| 324 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) | 348 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) |
| 325 columnSet->detachRegion(); | 349 columnSet->detachRegion(); |
| 326 multiColumnBlockFlow()->resetMultiColumnFlowThread(); | 350 multiColumnBlockFlow()->resetMultiColumnFlowThread(); |
| 327 RenderFlowThread::willBeRemovedFromTree(); | 351 RenderFlowThread::willBeRemovedFromTree(); |
| 328 } | 352 } |
| 329 | 353 |
| 354 LayoutUnit RenderMultiColumnFlowThread::skipColumnSpanner(RenderBox* renderer, L ayoutUnit logicalTopInFlowThread) | |
| 355 { | |
| 356 ASSERT(renderer->isColumnSpanAll()); | |
| 357 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlacehol der(); | |
| 358 LayoutUnit adjustment; | |
| 359 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); | |
| 360 if (previousColumnBox && previousColumnBox->isRenderMultiColumnSet()) { | |
| 361 // Pad flow thread offset to a column boundary, so that any column conte nt that's supposed | |
| 362 // to come after the spanner doesn't bleed into the column row preceding the spanner. | |
| 363 RenderMultiColumnSet* previousSet = toRenderMultiColumnSet(previousColum nBox); | |
| 364 if (previousSet->pageLogicalHeight()) { | |
| 365 LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTo pForOffset(logicalTopInFlowThread); | |
| 366 if (columnLogicalTopInFlowThread != logicalTopInFlowThread) { | |
| 367 adjustment = columnLogicalTopInFlowThread + previousSet->pageLog icalHeight() - logicalTopInFlowThread; | |
| 368 logicalTopInFlowThread += adjustment; | |
| 369 } | |
| 370 } | |
| 371 previousSet->endFlow(logicalTopInFlowThread); | |
| 372 } | |
| 373 RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox(); | |
| 374 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet()) { | |
| 375 RenderMultiColumnSet* nextSet = toRenderMultiColumnSet(nextColumnBox); | |
| 376 m_lastSetWorkedOn = nextSet; | |
| 377 nextSet->beginFlow(logicalTopInFlowThread); | |
| 378 } | |
| 379 return adjustment; | |
| 380 } | |
| 381 | |
| 330 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) | 382 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) |
| 331 { | 383 { |
| 332 ASSERT(!m_isBeingEvacuated); | 384 ASSERT(!m_isBeingEvacuated); |
| 333 // Go through the subtree that was just inserted and create column sets (nee ded by regular | 385 // 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). | 386 // column content) and spanner placeholders (one needed by each spanner). |
| 335 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { | 387 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { |
| 336 if (containingColumnSpannerPlaceholder(renderer)) | 388 if (containingColumnSpannerPlaceholder(renderer)) |
| 337 continue; // Inside a column spanner. Nothing to do, then. | 389 continue; // Inside a column spanner. Nothing to do, then. |
| 338 if (descendantIsValidColumnSpanner(renderer)) { | 390 if (descendantIsValidColumnSpanner(renderer)) { |
| 339 // This renderer is a spanner, so it needs to establish a spanner pl aceholder. | 391 // 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 | 435 |
| 384 void RenderMultiColumnFlowThread::updateLogicalWidth() | 436 void RenderMultiColumnFlowThread::updateLogicalWidth() |
| 385 { | 437 { |
| 386 LayoutUnit columnWidth; | 438 LayoutUnit columnWidth; |
| 387 calculateColumnCountAndWidth(columnWidth, m_columnCount); | 439 calculateColumnCountAndWidth(columnWidth, m_columnCount); |
| 388 setLogicalWidth(columnWidth); | 440 setLogicalWidth(columnWidth); |
| 389 } | 441 } |
| 390 | 442 |
| 391 void RenderMultiColumnFlowThread::layout() | 443 void RenderMultiColumnFlowThread::layout() |
| 392 { | 444 { |
| 445 ASSERT(!m_lastSetWorkedOn); | |
| 446 m_lastSetWorkedOn = firstMultiColumnSet(); | |
| 447 if (m_lastSetWorkedOn) | |
| 448 m_lastSetWorkedOn->beginFlow(LayoutUnit()); | |
| 393 RenderFlowThread::layout(); | 449 RenderFlowThread::layout(); |
| 394 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { | 450 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { |
| 395 if (!lastSet->nextSiblingMultiColumnBox()) | 451 ASSERT(lastSet == m_lastSetWorkedOn); |
| 452 if (!lastSet->nextSiblingMultiColumnBox()) { | |
| 453 lastSet->endFlow(logicalHeight()); | |
| 396 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); | 454 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); |
| 455 } | |
| 397 } | 456 } |
| 457 m_lastSetWorkedOn = 0; | |
| 398 } | 458 } |
| 399 | 459 |
| 400 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) | 460 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) |
| 401 { | 461 { |
| 402 // Only positive values are interesting (and allowed) here. Zero space short age may be reported | 462 // 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 | 463 // 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 | 464 // ignore any negative values, which may occur when we set an early break in order to honor |
| 405 // widows in the next column. | 465 // widows in the next column. |
| 406 if (spaceShortage <= 0) | 466 if (spaceShortage <= 0) |
| 407 return; | 467 return; |
| 408 | 468 |
| 409 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 469 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
| 410 multicolSet->recordSpaceShortage(spaceShortage); | 470 multicolSet->recordSpaceShortage(spaceShortage); |
| 411 } | 471 } |
| 412 | 472 |
| 413 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) | 473 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) |
| 414 { | 474 { |
| 415 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 475 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
| 416 multicolSet->updateMinimumColumnHeight(minHeight); | 476 multicolSet->updateMinimumColumnHeight(minHeight); |
| 417 } | 477 } |
| 418 | 478 |
| 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) | 479 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) |
| 426 { | 480 { |
| 427 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { | 481 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { |
| 428 multicolSet->addContentRun(offset); | 482 multicolSet->addContentRun(offset); |
| 429 if (offsetBreakAdjustment) | 483 if (offsetBreakAdjustment) |
| 430 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); | 484 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); |
| 431 return true; | 485 return true; |
| 432 } | 486 } |
| 433 return false; | 487 return false; |
| 434 } | 488 } |
| 435 | 489 |
| 436 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 490 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
| 437 { | 491 { |
| 438 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) | 492 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
| 439 return columnSet->pageLogicalHeight(); | 493 return columnSet->pageLogicalHeight(); |
| 440 return false; | 494 return false; |
| 441 } | 495 } |
| 442 | 496 |
| 443 } | 497 } |
| OLD | NEW |