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 10 matching lines...) Expand all Loading... |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/layout/LayoutMultiColumnFlowThread.h" | 27 #include "core/layout/LayoutMultiColumnFlowThread.h" |
28 | 28 |
29 #include "core/layout/LayoutMultiColumnSet.h" | 29 #include "core/layout/LayoutMultiColumnSet.h" |
30 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" | 30 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" |
| 31 #include "core/layout/MultiColumnFragmentainerGroup.h" |
31 | 32 |
32 namespace blink { | 33 namespace blink { |
33 | 34 |
34 LayoutMultiColumnFlowThread::LayoutMultiColumnFlowThread() | 35 LayoutMultiColumnFlowThread::LayoutMultiColumnFlowThread() |
35 : m_lastSetWorkedOn(nullptr) | 36 : m_lastSetWorkedOn(nullptr) |
36 , m_columnCount(1) | 37 , m_columnCount(1) |
37 , m_columnHeightAvailable(0) | 38 , m_columnHeightAvailable(0) |
38 , m_inBalancingPass(false) | 39 , m_inBalancingPass(false) |
39 , m_needsColumnHeightsRecalculation(false) | 40 , m_needsColumnHeightsRecalculation(false) |
40 , m_progressionIsInline(true) | 41 , m_progressionIsInline(true) |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 destroy(); | 264 destroy(); |
264 } | 265 } |
265 | 266 |
266 LayoutSize LayoutMultiColumnFlowThread::columnOffset(const LayoutPoint& point) c
onst | 267 LayoutSize LayoutMultiColumnFlowThread::columnOffset(const LayoutPoint& point) c
onst |
267 { | 268 { |
268 if (!hasValidColumnSetInfo()) | 269 if (!hasValidColumnSetInfo()) |
269 return LayoutSize(0, 0); | 270 return LayoutSize(0, 0); |
270 | 271 |
271 LayoutPoint flowThreadPoint = flipForWritingMode(point); | 272 LayoutPoint flowThreadPoint = flipForWritingMode(point); |
272 LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : f
lowThreadPoint.x(); | 273 LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : f
lowThreadPoint.x(); |
273 LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(blockOffset); | 274 return flowThreadTranslationAtOffset(blockOffset); |
274 if (!columnSet) | |
275 return LayoutSize(0, 0); | |
276 return columnSet->flowThreadTranslationAtOffset(blockOffset); | |
277 } | 275 } |
278 | 276 |
279 bool LayoutMultiColumnFlowThread::needsNewWidth() const | 277 bool LayoutMultiColumnFlowThread::needsNewWidth() const |
280 { | 278 { |
281 LayoutUnit newWidth; | 279 LayoutUnit newWidth; |
282 unsigned dummyColumnCount; // We only care if used column-width changes. | 280 unsigned dummyColumnCount; // We only care if used column-width changes. |
283 calculateColumnCountAndWidth(newWidth, dummyColumnCount); | 281 calculateColumnCountAndWidth(newWidth, dummyColumnCount); |
284 return newWidth != logicalWidth(); | 282 return newWidth != logicalWidth(); |
285 } | 283 } |
286 | 284 |
| 285 bool LayoutMultiColumnFlowThread::isPageLogicalHeightKnown() const |
| 286 { |
| 287 if (LayoutMultiColumnSet* columnSet = lastMultiColumnSet()) |
| 288 return columnSet->isPageLogicalHeightKnown(); |
| 289 return false; |
| 290 } |
| 291 |
| 292 LayoutSize LayoutMultiColumnFlowThread::flowThreadTranslationAtOffset(LayoutUnit
offsetInFlowThread) const |
| 293 { |
| 294 LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(offsetInFlowThread)
; |
| 295 if (!columnSet) |
| 296 return LayoutSize(0, 0); |
| 297 return columnSet->flowThreadTranslationAtOffset(offsetInFlowThread); |
| 298 } |
| 299 |
287 LayoutPoint LayoutMultiColumnFlowThread::visualPointToFlowThreadPoint(const Layo
utPoint& visualPoint) const | 300 LayoutPoint LayoutMultiColumnFlowThread::visualPointToFlowThreadPoint(const Layo
utPoint& visualPoint) const |
288 { | 301 { |
289 LayoutUnit blockOffset = isHorizontalWritingMode() ? visualPoint.y() : visua
lPoint.x(); | 302 LayoutUnit blockOffset = isHorizontalWritingMode() ? visualPoint.y() : visua
lPoint.x(); |
290 const LayoutMultiColumnSet* columnSet = nullptr; | 303 const LayoutMultiColumnSet* columnSet = nullptr; |
291 for (const LayoutMultiColumnSet* candidate = firstMultiColumnSet(); candidat
e; candidate = candidate->nextSiblingMultiColumnSet()) { | 304 for (const LayoutMultiColumnSet* candidate = firstMultiColumnSet(); candidat
e; candidate = candidate->nextSiblingMultiColumnSet()) { |
292 columnSet = candidate; | 305 columnSet = candidate; |
293 if (candidate->logicalBottom() > blockOffset) | 306 if (candidate->logicalBottom() > blockOffset) |
294 break; | 307 break; |
295 } | 308 } |
296 return columnSet ? columnSet->visualPointToFlowThreadPoint(toLayoutPoint(vis
ualPoint + location() - columnSet->location())) : visualPoint; | 309 return columnSet ? columnSet->visualPointToFlowThreadPoint(toLayoutPoint(vis
ualPoint + location() - columnSet->location())) : visualPoint; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 if (!needsLayout()) { | 350 if (!needsLayout()) { |
338 // Just before the multicol container (our parent LayoutBlockFlow) finis
hes laying out, it | 351 // Just before the multicol container (our parent LayoutBlockFlow) finis
hes laying out, it |
339 // will call recalculateColumnHeights() on us unconditionally, but we on
ly want that method | 352 // will call recalculateColumnHeights() on us unconditionally, but we on
ly want that method |
340 // to do any work if we actually laid out the flow thread. Otherwise, th
e balancing | 353 // to do any work if we actually laid out the flow thread. Otherwise, th
e balancing |
341 // machinery would kick in needlessly, and trigger additional layout pas
ses. Furthermore, we | 354 // machinery would kick in needlessly, and trigger additional layout pas
ses. Furthermore, we |
342 // actually depend on a proper flowthread layout pass in order to do bal
ancing, since it's | 355 // actually depend on a proper flowthread layout pass in order to do bal
ancing, since it's |
343 // flowthread layout that sets up content runs. | 356 // flowthread layout that sets up content runs. |
344 return; | 357 return; |
345 } | 358 } |
346 | 359 |
| 360 m_blockOffsetInEnclosingFlowThread = enclosingFlowThread() ? multiColumnBloc
kFlow()->offsetFromLogicalTopOfFirstPage() : LayoutUnit(); |
| 361 |
347 for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co
lumnBox->nextSiblingMultiColumnBox()) { | 362 for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = co
lumnBox->nextSiblingMultiColumnBox()) { |
348 if (!columnBox->isLayoutMultiColumnSet()) { | 363 if (!columnBox->isLayoutMultiColumnSet()) { |
349 ASSERT(columnBox->isLayoutMultiColumnSpannerPlaceholder()); // no ot
her type is expected. | 364 ASSERT(columnBox->isLayoutMultiColumnSpannerPlaceholder()); // no ot
her type is expected. |
350 m_needsColumnHeightsRecalculation = true; | 365 m_needsColumnHeightsRecalculation = true; |
351 continue; | 366 continue; |
352 } | 367 } |
353 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox); | 368 LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox); |
354 if (!m_inBalancingPass) { | 369 if (!m_inBalancingPass) { |
355 // This is the initial layout pass. We need to reset the column heig
ht, because contents | 370 // This is the initial layout pass. We need to reset the column heig
ht, because contents |
356 // typically have changed. | 371 // typically have changed. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 | 429 |
415 // We may have a new containing block, since we're no longer a spanner. Mark
it for relayout. | 430 // We may have a new containing block, since we're no longer a spanner. Mark
it for relayout. |
416 spannerObjectInFlowThread->containingBlock()->setNeedsLayoutAndPrefWidthsRec
alc(LayoutInvalidationReason::ColumnsChanged); | 431 spannerObjectInFlowThread->containingBlock()->setNeedsLayoutAndPrefWidthsRec
alc(LayoutInvalidationReason::ColumnsChanged); |
417 | 432 |
418 // Now generate a column set for this ex-spanner, if needed and none is ther
e for us already. | 433 // Now generate a column set for this ex-spanner, if needed and none is ther
e for us already. |
419 flowThreadDescendantWasInserted(spannerObjectInFlowThread); | 434 flowThreadDescendantWasInserted(spannerObjectInFlowThread); |
420 | 435 |
421 return true; | 436 return true; |
422 } | 437 } |
423 | 438 |
| 439 LayoutMultiColumnFlowThread* LayoutMultiColumnFlowThread::enclosingFlowThread()
const |
| 440 { |
| 441 if (multiColumnBlockFlow()->isInsideFlowThread()) |
| 442 return toLayoutMultiColumnFlowThread(locateFlowThreadContainingBlockOf(*
multiColumnBlockFlow())); |
| 443 return nullptr; |
| 444 } |
| 445 |
| 446 bool LayoutMultiColumnFlowThread::hasFragmentainerGroupForColumnAt(LayoutUnit of
fsetInFlowThread) const |
| 447 { |
| 448 // If there's no enclosing flow thread, there'll always be only one fragment
ainer group, and it |
| 449 // can hold as many columns as we like. We shouldn't even be here in that ca
se. |
| 450 ASSERT(enclosingFlowThread()); |
| 451 |
| 452 LayoutMultiColumnSet* lastColumnSet = lastMultiColumnSet(); |
| 453 if (!lastColumnSet) { |
| 454 ASSERT_NOT_REACHED(); |
| 455 return true; |
| 456 } |
| 457 if (lastColumnSet->logicalTopInFlowThread() > offsetInFlowThread) |
| 458 return true; |
| 459 const MultiColumnFragmentainerGroup& lastRow = lastColumnSet->lastFragmentai
nerGroup(); |
| 460 if (lastRow.logicalTopInFlowThread() > offsetInFlowThread) |
| 461 return true; |
| 462 return offsetInFlowThread - lastRow.logicalTopInFlowThread() < lastRow.logic
alHeight() * lastColumnSet->usedColumnCount(); |
| 463 } |
| 464 |
| 465 void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit
offsetInFlowThread) |
| 466 { |
| 467 LayoutMultiColumnFlowThread* enclosingFlowThread = this->enclosingFlowThread
(); |
| 468 if (!enclosingFlowThread) |
| 469 return; // Not nested. We'll never need more rows than the one we alread
y have then. |
| 470 if (!hasFragmentainerGroupForColumnAt(offsetInFlowThread)) { |
| 471 // We have run out of columns here, so we add another row to hold more c
olumns. When we add |
| 472 // a new row, it implicitly means that we're inserting another column in
our enclosing |
| 473 // multicol container. That in turn may mean that we've run out of colum
ns there too. |
| 474 const MultiColumnFragmentainerGroup& newRow = lastMultiColumnSet()->appe
ndNewFragmentainerGroup(); |
| 475 enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOff
setInEnclosingFlowThread()); |
| 476 } |
| 477 } |
| 478 |
424 void LayoutMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width
, unsigned& count) const | 479 void LayoutMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width
, unsigned& count) const |
425 { | 480 { |
426 LayoutBlock* columnBlock = multiColumnBlockFlow(); | 481 LayoutBlock* columnBlock = multiColumnBlockFlow(); |
427 const ComputedStyle* columnStyle = columnBlock->style(); | 482 const ComputedStyle* columnStyle = columnBlock->style(); |
428 LayoutUnit availableWidth = columnBlock->contentLogicalWidth(); | 483 LayoutUnit availableWidth = columnBlock->contentLogicalWidth(); |
429 LayoutUnit columnGap = columnBlock->columnGap(); | 484 LayoutUnit columnGap = columnBlock->columnGap(); |
430 LayoutUnit computedColumnWidth = max<LayoutUnit>(1, LayoutUnit(columnStyle->
columnWidth())); | 485 LayoutUnit computedColumnWidth = max<LayoutUnit>(1, LayoutUnit(columnStyle->
columnWidth())); |
431 unsigned computedColumnCount = max<int>(1, columnStyle->columnCount()); | 486 unsigned computedColumnCount = max<int>(1, columnStyle->columnCount()); |
432 | 487 |
433 ASSERT(!columnStyle->hasAutoColumnCount() || !columnStyle->hasAutoColumnWidt
h()); | 488 ASSERT(!columnStyle->hasAutoColumnCount() || !columnStyle->hasAutoColumnWidt
h()); |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 { | 964 { |
910 if (LayoutMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { | 965 if (LayoutMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { |
911 multicolSet->addContentRun(offset); | 966 multicolSet->addContentRun(offset); |
912 if (offsetBreakAdjustment) | 967 if (offsetBreakAdjustment) |
913 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe
mainingLogicalHeightForOffset(offset, AssociateWithFormerPage) : LayoutUnit(); | 968 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe
mainingLogicalHeightForOffset(offset, AssociateWithFormerPage) : LayoutUnit(); |
914 return true; | 969 return true; |
915 } | 970 } |
916 return false; | 971 return false; |
917 } | 972 } |
918 | 973 |
919 bool LayoutMultiColumnFlowThread::isPageLogicalHeightKnown() const | |
920 { | |
921 if (LayoutMultiColumnSet* columnSet = lastMultiColumnSet()) | |
922 return columnSet->isPageLogicalHeightKnown(); | |
923 return false; | |
924 } | |
925 | |
926 } | 974 } |
OLD | NEW |