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/RenderMultiColumnSpannerSet.h" | 30 #include "core/rendering/RenderMultiColumnSpannerSet.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 { | 41 { |
| 41 setFlowThreadState(InsideInFlowThread); | 42 setFlowThreadState(InsideInFlowThread); |
| 42 } | 43 } |
| 43 | 44 |
| 44 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() | 45 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() |
| 45 { | 46 { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 // Just before the multicol container (our parent RenderBlockFlow) finis hes laying out, it | 156 // Just before the multicol container (our parent RenderBlockFlow) finis hes laying out, it |
| 156 // will call recalculateColumnHeights() on us unconditionally, but we on ly want that method | 157 // will call recalculateColumnHeights() on us unconditionally, but we on ly want that method |
| 157 // to do any work if we actually laid out the flow thread. Otherwise, th e balancing | 158 // to do any work if we actually laid out the flow thread. Otherwise, th e balancing |
| 158 // machinery would kick in needlessly, and trigger additional layout pas ses. Furthermore, we | 159 // machinery would kick in needlessly, and trigger additional layout pas ses. Furthermore, we |
| 159 // actually depend on a proper flowthread layout pass in order to do bal ancing, since it's | 160 // actually depend on a proper flowthread layout pass in order to do bal ancing, since it's |
| 160 // flowthread layout that sets up content runs. | 161 // flowthread layout that sets up content runs. |
| 161 m_needsColumnHeightsRecalculation = false; | 162 m_needsColumnHeightsRecalculation = false; |
| 162 return; | 163 return; |
| 163 } | 164 } |
| 164 | 165 |
| 165 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) { | 166 if (!m_inBalancingPass) { |
| 166 if (!m_inBalancingPass) { | 167 // This is the initial layout pass. We need to reset the column height, because contents |
| 167 // This is the initial layout pass. We need to reset the column heig ht, because contents | 168 // typically have changed. |
| 168 // typically have changed. | 169 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) |
| 169 columnSet->resetColumnHeight(); | 170 columnSet->resetColumnHeight(); |
| 170 } | |
| 171 } | 171 } |
| 172 | 172 |
| 173 invalidateRegions(); | 173 invalidateRegions(); |
| 174 m_needsColumnHeightsRecalculation = heightIsAuto(); | 174 m_needsColumnHeightsRecalculation = true; |
| 175 layout(); | 175 layout(); |
| 176 } | 176 } |
| 177 | 177 |
| 178 bool RenderMultiColumnFlowThread::recalculateColumnHeights() | 178 bool RenderMultiColumnFlowThread::recalculateColumnHeights() |
| 179 { | 179 { |
| 180 // All column sets that needed layout have now been laid out, so we can fina lly validate them. | 180 // All column sets that needed layout have now been laid out, so we can fina lly validate them. |
| 181 validateRegions(); | 181 validateRegions(); |
| 182 | 182 |
| 183 if (!m_needsColumnHeightsRecalculation) | 183 if (!m_needsColumnHeightsRecalculation) |
| 184 return false; | 184 return false; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 m_spannerMap.clear(); | 309 m_spannerMap.clear(); |
| 310 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they | 310 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they |
| 311 // are siblings of this object, and there may be pointers to this object's s ibling somewhere | 311 // are siblings of this object, and there may be pointers to this object's s ibling somewhere |
| 312 // further up on the call stack. | 312 // further up on the call stack. |
| 313 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) | 313 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) |
| 314 columnSet->detachRegion(); | 314 columnSet->detachRegion(); |
| 315 multiColumnBlockFlow()->resetMultiColumnFlowThread(); | 315 multiColumnBlockFlow()->resetMultiColumnFlowThread(); |
| 316 RenderFlowThread::willBeRemovedFromTree(); | 316 RenderFlowThread::willBeRemovedFromTree(); |
| 317 } | 317 } |
| 318 | 318 |
| 319 bool RenderMultiColumnFlowThread::isColumnSpanner(const RenderObject* descendant ) const | |
| 320 { | |
| 321 ASSERT(descendant->isDescendantOf(this)); | |
| 322 return m_spannerMap.get(descendant); | |
| 323 } | |
| 324 | |
| 325 bool RenderMultiColumnFlowThread::isInsideColumnSpanner(const RenderObject* desc endant) const | |
| 326 { | |
| 327 ASSERT(descendant->isDescendantOf(this)); | |
| 328 return containingColumnSpannerSet(descendant); | |
| 329 } | |
| 330 | |
| 331 LayoutUnit RenderMultiColumnFlowThread::enterColumnSpannerBeforeLayout(RenderBox * renderer, LayoutUnit logicalTop, SubtreeLayoutScope& layoutScope) | |
| 332 { | |
| 333 ASSERT(renderer->isDescendantOf(this)); | |
| 334 RenderMultiColumnSpannerSet* spannerSet = m_spannerMap.get(renderer); | |
| 335 ASSERT(spannerSet); | |
| 336 | |
| 337 // FIXME: it's really only necessary to mark the spanner set for layout when the height of | |
| 338 // |renderer| changes. | |
| 339 spannerSet->setChildNeedsLayout(MarkOnlyThis, &layoutScope); | |
| 340 | |
| 341 RenderMultiColumnSet* previousSet = spannerSet->previousSiblingMultiColumnSe t(); | |
| 342 if (!previousSet) { | |
| 343 // The first set is entered at the beginning of flow thread layout. If t he first set happens | |
| 344 // to be a spanner, we have nothing more to do here. | |
| 345 return LayoutUnit(); | |
| 346 } | |
| 347 | |
| 348 RenderBlock* cb = renderer->containingBlock(); | |
| 349 LayoutUnit logicalTopInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalTop; | |
| 350 LayoutUnit adjustment; | |
| 351 if (!previousSet->isRenderMultiColumnSpannerSet() && previousSet->pageLogica lHeight()) { | |
| 352 // Pad flow thread offset to a column boundary, so that contents that's supposed to come | |
| 353 // after the spanner (or the spanner itself) don't bleed into the column preceding the | |
| 354 // spanner. | |
| 355 LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTopFor Offset(logicalTopInFlowThread); | |
| 356 if (columnLogicalTopInFlowThread != logicalTopInFlowThread) { | |
| 357 adjustment = columnLogicalTopInFlowThread + previousSet->pageLogical Height() - logicalTopInFlowThread; | |
| 358 logicalTopInFlowThread += adjustment; | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 if (!previousSet->isRenderMultiColumnSpannerSet()) | |
| 363 previousSet->endFlow(logicalTopInFlowThread); | |
| 364 spannerSet->beginFlow(logicalTopInFlowThread); | |
| 365 | |
| 366 m_lastSetWorkedOn = spannerSet; | |
| 367 return adjustment; | |
| 368 } | |
| 369 | |
| 370 void RenderMultiColumnFlowThread::leaveColumnSpannerAfterLayout(RenderBox* rende rer, LayoutUnit logicalBottom) | |
| 371 { | |
| 372 ASSERT(m_lastSetWorkedOn == m_spannerMap.get(renderer)); | |
| 373 | |
| 374 RenderBlock* cb = renderer->containingBlock(); | |
| 375 LayoutUnit logicalBottomInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalBottom; | |
| 376 m_lastSetWorkedOn->endFlow(logicalBottomInFlowThread); | |
| 377 RenderMultiColumnSet* nextSet = m_lastSetWorkedOn->nextSiblingMultiColumnSet (); | |
| 378 if (nextSet) { | |
| 379 m_lastSetWorkedOn = nextSet; | |
| 380 if (!m_lastSetWorkedOn->isRenderMultiColumnSpannerSet()) | |
| 381 m_lastSetWorkedOn->beginFlow(logicalBottomInFlowThread); | |
| 382 } | |
| 383 } | |
| 384 | |
| 319 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) | 385 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) |
| 320 { | 386 { |
| 321 // 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 |
| 322 // column content) and spanner sets (one needed by each spanner). | 388 // column content) and spanner sets (one needed by each spanner). |
| 323 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { | 389 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { |
| 324 if (containingColumnSpannerSet(renderer)) | 390 if (containingColumnSpannerSet(renderer)) |
| 325 continue; // Inside a column spanner set. Nothing to do, then. | 391 continue; // Inside a column spanner set. Nothing to do, then. |
| 326 if (descendantIsValidColumnSpanner(renderer)) { | 392 if (descendantIsValidColumnSpanner(renderer)) { |
| 327 // This renderer is a spanner, so it needs to establish a spanner se t. | 393 // This renderer is a spanner, so it needs to establish a spanner se t. |
| 328 createAndInsertSpannerSet(toRenderBox(renderer)); | 394 createAndInsertSpannerSet(toRenderBox(renderer)); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 344 | 410 |
| 345 void RenderMultiColumnFlowThread::updateLogicalWidth() | 411 void RenderMultiColumnFlowThread::updateLogicalWidth() |
| 346 { | 412 { |
| 347 LayoutUnit columnWidth; | 413 LayoutUnit columnWidth; |
| 348 calculateColumnCountAndWidth(columnWidth, m_columnCount); | 414 calculateColumnCountAndWidth(columnWidth, m_columnCount); |
| 349 setLogicalWidth(columnWidth); | 415 setLogicalWidth(columnWidth); |
| 350 } | 416 } |
| 351 | 417 |
| 352 void RenderMultiColumnFlowThread::layout() | 418 void RenderMultiColumnFlowThread::layout() |
| 353 { | 419 { |
| 420 ASSERT(!m_lastSetWorkedOn); | |
| 421 m_lastSetWorkedOn = firstMultiColumnSet(); | |
| 422 if (m_lastSetWorkedOn) | |
| 423 m_lastSetWorkedOn->beginFlow(LayoutUnit()); | |
| 354 RenderFlowThread::layout(); | 424 RenderFlowThread::layout(); |
| 355 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) | 425 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { |
| 426 lastSet->endFlow(logicalHeight()); | |
| 356 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); | 427 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); |
| 428 } | |
| 429 m_lastSetWorkedOn = 0; | |
| 357 } | 430 } |
| 358 | 431 |
| 359 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) | 432 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) |
| 360 { | 433 { |
| 361 // Only positive values are interesting (and allowed) here. Zero space short age may be reported | 434 // Only positive values are interesting (and allowed) here. Zero space short age may be reported |
| 362 // when we're at the top of a column and the element has zero height. Ignore this, and also | 435 // when we're at the top of a column and the element has zero height. Ignore this, and also |
| 363 // ignore any negative values, which may occur when we set an early break in order to honor | 436 // ignore any negative values, which may occur when we set an early break in order to honor |
| 364 // widows in the next column. | 437 // widows in the next column. |
| 365 if (spaceShortage <= 0) | 438 if (spaceShortage <= 0) |
| 366 return; | 439 return; |
| 367 | 440 |
| 368 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 441 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
| 369 multicolSet->recordSpaceShortage(spaceShortage); | 442 multicolSet->recordSpaceShortage(spaceShortage); |
| 370 } | 443 } |
| 371 | 444 |
| 372 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) | 445 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) |
| 373 { | 446 { |
| 374 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) | 447 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) |
| 375 multicolSet->updateMinimumColumnHeight(minHeight); | 448 multicolSet->updateMinimumColumnHeight(minHeight); |
| 376 } | 449 } |
| 377 | 450 |
| 378 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit /*offset*/) const | 451 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit offset) const |
| 379 { | 452 { |
| 380 // For now there's only one column set, so this is easy: | 453 if (m_lastSetWorkedOn) { |
| 381 return firstMultiColumnSet(); | 454 // Layout in progress. We are calculating the set heights as we speak, s o the column set range |
| 455 // information is not up-to-date. | |
| 456 // FIXME: need to check if m_lastSetWorkedOn contains the offset, and if it doesn't, we need | |
| 457 // to locate the right set. | |
| 458 return m_lastSetWorkedOn; | |
| 459 } | |
| 460 | |
| 461 ASSERT(!m_regionsInvalidated); | |
| 462 if (offset <= 0) | |
| 463 return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first() ; | |
| 464 | |
| 465 MultiColumnSetSearchAdapter adapter(offset); | |
|
mstensho (USE GERRIT)
2014/11/07 16:06:01
Note: The code here is a revival of code found ori
| |
| 466 m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdap ter>(adapter); | |
| 467 | |
| 468 // If no set was found, the offset is in the flow thread overflow. | |
| 469 if (!adapter.result() && !m_multiColumnSetList.isEmpty()) | |
| 470 return m_multiColumnSetList.last(); | |
| 471 return adapter.result(); | |
| 382 } | 472 } |
| 383 | 473 |
| 384 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) | 474 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) |
| 385 { | 475 { |
| 386 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { | 476 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { |
| 387 multicolSet->addContentRun(offset); | 477 multicolSet->addContentRun(offset); |
| 388 if (offsetBreakAdjustment) | 478 if (offsetBreakAdjustment) |
| 389 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); | 479 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); |
| 390 return true; | 480 return true; |
| 391 } | 481 } |
| 392 return false; | 482 return false; |
| 393 } | 483 } |
| 394 | 484 |
| 395 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 485 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
| 396 { | 486 { |
| 397 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) | 487 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
| 398 return columnSet->pageLogicalHeight(); | 488 return columnSet->pageLogicalHeight(); |
| 399 return false; | 489 return false; |
| 400 } | 490 } |
| 401 | 491 |
| 402 } | 492 } |
| OLD | NEW |