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 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
314 width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnG ap)) / count); | 314 width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnG ap)) / count); |
315 } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnC ount()) { | 315 } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnC ount()) { |
316 count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computed ColumnWidth + columnGap)); | 316 count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computed ColumnWidth + columnGap)); |
317 width = ((availableWidth + columnGap) / count) - columnGap; | 317 width = ((availableWidth + columnGap) / count) - columnGap; |
318 } else { | 318 } else { |
319 count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, ( availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1); | 319 count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, ( availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1); |
320 width = ((availableWidth + columnGap) / count) - columnGap; | 320 width = ((availableWidth + columnGap) / count) - columnGap; |
321 } | 321 } |
322 } | 322 } |
323 | 323 |
324 void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet() | 324 void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet(RenderBox* inser tBefore) |
325 { | 325 { |
326 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); | 326 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
327 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, m ulticolContainer->style()); | 327 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, m ulticolContainer->style()); |
328 multicolContainer->RenderBlock::addChild(newSet); | 328 multicolContainer->RenderBlock::addChild(newSet, insertBefore); |
329 invalidateRegions(); | 329 invalidateRegions(); |
330 | 330 |
331 // We cannot handle immediate column set siblings (and there's no need for i t, either). | 331 // We cannot handle immediate column set siblings (and there's no need for i t, either). |
332 // There has to be at least one spanner separating them. | 332 // There has to be at least one spanner separating them. |
333 ASSERT(!newSet->previousSiblingMultiColumnBox() || !newSet->previousSiblingM ultiColumnBox()->isRenderMultiColumnSet()); | 333 ASSERT(!newSet->previousSiblingMultiColumnBox() || !newSet->previousSiblingM ultiColumnBox()->isRenderMultiColumnSet()); |
334 ASSERT(!newSet->nextSiblingMultiColumnBox() || !newSet->nextSiblingMultiColu mnBox()->isRenderMultiColumnSet()); | 334 ASSERT(!newSet->nextSiblingMultiColumnBox() || !newSet->nextSiblingMultiColu mnBox()->isRenderMultiColumnSet()); |
335 } | 335 } |
336 | 336 |
337 void RenderMultiColumnFlowThread::createAndInsertSpannerPlaceholder(RenderBox* s panner) | 337 void RenderMultiColumnFlowThread::createAndInsertSpannerPlaceholder(RenderBox* s panner, RenderBox* insertBefore) |
338 { | 338 { |
339 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); | 339 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
340 RenderMultiColumnSpannerPlaceholder* newPlaceholder = RenderMultiColumnSpann erPlaceholder::createAnonymous(multicolContainer->style(), spanner); | 340 RenderMultiColumnSpannerPlaceholder* newPlaceholder = RenderMultiColumnSpann erPlaceholder::createAnonymous(multicolContainer->style(), spanner); |
341 multicolContainer->RenderBlock::addChild(newPlaceholder); | 341 multicolContainer->RenderBlock::addChild(newPlaceholder, insertBefore); |
342 spanner->setSpannerPlaceholder(*newPlaceholder); | 342 spanner->setSpannerPlaceholder(*newPlaceholder); |
343 } | 343 } |
344 | 344 |
345 bool RenderMultiColumnFlowThread::descendantIsValidColumnSpanner(RenderObject* d escendant) const | 345 bool RenderMultiColumnFlowThread::descendantIsValidColumnSpanner(RenderObject* d escendant) const |
346 { | 346 { |
347 // We assume that we're inside the flow thread. This function is not to be c alled otherwise. | 347 // We assume that we're inside the flow thread. This function is not to be c alled otherwise. |
348 ASSERT(descendant->isDescendantOf(this)); | 348 ASSERT(descendant->isDescendantOf(this)); |
349 | 349 |
350 // We're evaluating if the descendant should be turned into a proper spanner . It shouldn't | 350 // We're evaluating if the descendant should be turned into a proper spanner . It shouldn't |
351 // already be one. | 351 // already be one. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
434 RenderMultiColumnSet* nextSet = toRenderMultiColumnSet(nextColumnBox); | 434 RenderMultiColumnSet* nextSet = toRenderMultiColumnSet(nextColumnBox); |
435 m_lastSetWorkedOn = nextSet; | 435 m_lastSetWorkedOn = nextSet; |
436 nextSet->beginFlow(logicalTopInFlowThread); | 436 nextSet->beginFlow(logicalTopInFlowThread); |
437 } | 437 } |
438 return adjustment; | 438 return adjustment; |
439 } | 439 } |
440 | 440 |
441 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) | 441 void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) |
442 { | 442 { |
443 ASSERT(!m_isBeingEvacuated); | 443 ASSERT(!m_isBeingEvacuated); |
444 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this); | |
444 // Go through the subtree that was just inserted and create column sets (nee ded by regular | 445 // Go through the subtree that was just inserted and create column sets (nee ded by regular |
445 // column content) and spanner placeholders (one needed by each spanner). | 446 // column content) and spanner placeholders (one needed by each spanner). |
446 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { | 447 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { |
447 if (containingColumnSpannerPlaceholder(renderer)) | 448 if (containingColumnSpannerPlaceholder(renderer)) |
448 continue; // Inside a column spanner. Nothing to do, then. | 449 continue; // Inside a column spanner. Nothing to do, then. |
449 if (descendantIsValidColumnSpanner(renderer)) { | 450 if (descendantIsValidColumnSpanner(renderer)) { |
450 // This renderer is a spanner, so it needs to establish a spanner pl aceholder. | 451 // This renderer is a spanner, so it needs to establish a spanner pl aceholder. |
451 createAndInsertSpannerPlaceholder(toRenderBox(renderer)); | 452 RenderBox* insertBefore = 0; |
453 RenderMultiColumnSet* setToSplit = 0; | |
454 if (nextRenderer) { | |
455 // The spanner is inserted before something. Figure out what thi s entails. If the | |
456 // next renderer is a spanner too, it means that we can simply i nsert a new spanner | |
457 // placeholder in front of its placeholder. | |
458 insertBefore = nextRenderer->spannerPlaceholder(); | |
459 if (!insertBefore) { | |
460 // The next renderer isn't a spanner; it's regular column co ntent. Examine what | |
461 // comes right before us, then. | |
462 RenderObject* previousRenderer = renderer->previousInPreOrde r(this); | |
Julien - ping for review
2015/01/23 09:13:56
You're using |this| as the |root| instead of |desc
mstensho (USE GERRIT)
2015/01/23 12:15:49
Yes, |this| is the flow thread, and that's all we
| |
463 if (!previousRenderer || previousRenderer == this) { | |
464 // The spanner is inserted as the first child of the mul ticol container, | |
465 // which means that we simply insert a new spanner place holder at the | |
466 // beginning. | |
467 insertBefore = firstMultiColumnBox(); | |
468 } else if (RenderMultiColumnSpannerPlaceholder* previousPlac eholder = containingColumnSpannerPlaceholder(previousRenderer)) { | |
469 // Before us is another spanner. We belong right after i t then. | |
470 insertBefore = previousPlaceholder->nextSiblingMultiColu mnBox(); | |
471 } else { | |
472 // We're inside regular column content with both feet. F ind out which column | |
473 // set this is. It needs to be split it into two sets, s o that we can insert | |
474 // a new spanner placeholder between them. | |
475 setToSplit = findSetRendering(previousRenderer); | |
476 ASSERT(setToSplit == findSetRendering(nextRenderer)); | |
477 setToSplit->setNeedsLayoutAndFullPaintInvalidation(); | |
478 insertBefore = setToSplit->nextSiblingMultiColumnBox(); | |
479 // We've found out which set that needs to be split. Now proceed to | |
480 // inserting the spanner placeholder, and then insert a second column set. | |
481 } | |
482 } | |
483 ASSERT(setToSplit || insertBefore); | |
484 } | |
485 createAndInsertSpannerPlaceholder(toRenderBox(renderer), insertBefor e); | |
486 if (setToSplit) | |
487 createAndInsertMultiColumnSet(insertBefore); | |
452 continue; | 488 continue; |
453 } | 489 } |
454 // This renderer is regular column content (i.e. not a spanner). Create a set if necessary. | 490 // This renderer is regular column content (i.e. not a spanner). Create a set if necessary. |
455 RenderBox* lastColumnBox = lastMultiColumnBox(); | 491 if (nextRenderer) { |
456 if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet()) | 492 if (RenderMultiColumnSpannerPlaceholder* placeholder = nextRenderer- >spannerPlaceholder()) { |
457 createAndInsertMultiColumnSet(); | 493 // If inserted right before a spanner, we need to make sure that there's a set for us there. |
494 RenderBox* previous = placeholder->previousSiblingMultiColumnBox (); | |
495 if (!previous || !previous->isRenderMultiColumnSet()) | |
496 createAndInsertMultiColumnSet(placeholder); | |
497 } else { | |
498 // Otherwise, since |nextRenderer| isn't a spanner, it has to me an that there's | |
499 // already a set for that content. We can use it for this render er too. | |
500 ASSERT(findSetRendering(nextRenderer)); | |
501 ASSERT(findSetRendering(renderer) == findSetRendering(nextRender er)); | |
502 } | |
503 } else { | |
504 // Inserting at the end. Then we just need to make sure that there's a column set at the end. | |
505 RenderBox* lastColumnBox = lastMultiColumnBox(); | |
506 if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet()) | |
507 createAndInsertMultiColumnSet(); | |
508 } | |
458 } | 509 } |
459 } | 510 } |
460 | 511 |
461 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant) | 512 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant) |
462 { | 513 { |
463 if (m_isBeingEvacuated) | 514 if (m_isBeingEvacuated) |
464 return; | 515 return; |
516 bool hadContainingPlaceholder = containingColumnSpannerPlaceholder(descendan t); | |
465 RenderObject* next; | 517 RenderObject* next; |
466 // Remove spanner placeholders that are no longer needed, and merge column s ets around them. | 518 // Remove spanner placeholders that are no longer needed, and merge column s ets around them. |
467 for (RenderObject* renderer = descendant; renderer; renderer = next) { | 519 for (RenderObject* renderer = descendant; renderer; renderer = next) { |
468 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlac eholder(); | 520 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlac eholder(); |
469 if (!placeholder) { | 521 if (!placeholder) { |
470 next = renderer->nextInPreOrder(descendant); | 522 next = renderer->nextInPreOrder(descendant); |
471 continue; | 523 continue; |
472 } | 524 } |
473 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us. | 525 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us. |
474 if (RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox()) { | 526 if (RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox()) { |
475 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColu mnBox(); | 527 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColu mnBox(); |
476 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet() | 528 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet() |
477 && previousColumnBox && previousColumnBox->isRenderMultiColumnSe t()) { | 529 && previousColumnBox && previousColumnBox->isRenderMultiColumnSe t()) { |
478 // Need to merge two column sets. | 530 // Need to merge two column sets. |
479 nextColumnBox->destroy(); | 531 nextColumnBox->destroy(); |
480 previousColumnBox->setNeedsLayout(); | 532 previousColumnBox->setNeedsLayout(); |
481 invalidateRegions(); | 533 invalidateRegions(); |
482 } | 534 } |
483 } | 535 } |
484 placeholder->destroy(); | 536 placeholder->destroy(); |
485 } | 537 } |
538 if (hadContainingPlaceholder) | |
539 return; // We're only removing a spanner (or something inside one), whic h means that no column content will be removed. | |
540 | |
541 // Column content will be removed. Does this mean that we should destroy a c olumn set? | |
542 RenderMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = 0; | |
543 RenderObject* previousRenderer = descendant->previousInPreOrder(this); | |
544 if (previousRenderer && previousRenderer != this) { | |
545 adjacentPreviousSpannerPlaceholder = containingColumnSpannerPlaceholder( previousRenderer); | |
546 if (!adjacentPreviousSpannerPlaceholder) | |
547 return; // Preceded by column content. Set still needed. | |
548 } | |
549 RenderMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = 0; | |
550 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this); | |
551 if (nextRenderer) { | |
552 adjacentNextSpannerPlaceholder = containingColumnSpannerPlaceholder(next Renderer); | |
553 if (!adjacentNextSpannerPlaceholder) | |
554 return; // Followed by column content. Set still needed. | |
555 } | |
Julien - ping for review
2015/01/23 09:13:56
Shouldn't you ASSERT that you either have no child
mstensho (USE GERRIT)
2015/01/23 12:15:50
Discussed offline that what we already have is eno
| |
556 // We have now determined that, with the removal of |descendant|, we should remove a column | |
557 // set. Locate it and remove it. Do it without involving findSetRendering(), as that might be | |
558 // very slow. Deduce the right set from the spanner placeholders that we've already found. | |
559 RenderMultiColumnSet* columnSetToRemove; | |
560 if (adjacentNextSpannerPlaceholder) { | |
561 columnSetToRemove = toRenderMultiColumnSet(adjacentNextSpannerPlaceholde r->previousSiblingMultiColumnBox()); | |
562 ASSERT(!adjacentPreviousSpannerPlaceholder || columnSetToRemove == adjac entPreviousSpannerPlaceholder->nextSiblingMultiColumnBox()); | |
563 } else if (adjacentPreviousSpannerPlaceholder) { | |
564 columnSetToRemove = toRenderMultiColumnSet(adjacentPreviousSpannerPlaceh older->nextSiblingMultiColumnBox()); | |
565 } else { | |
566 // If there were no adjacent spanners, it has to mean that there's only one column set, | |
567 // since it's only spanners that may cause creation of multiple sets. | |
568 columnSetToRemove = firstMultiColumnSet(); | |
569 ASSERT(columnSetToRemove && !columnSetToRemove->nextSiblingMultiColumnSe t()); | |
570 } | |
571 ASSERT(columnSetToRemove); | |
572 columnSetToRemove->destroy(); | |
486 } | 573 } |
Julien - ping for review
2015/01/23 09:13:56
Adding a comment to explain the whole strategy wou
mstensho (USE GERRIT)
2015/01/23 12:15:49
Done.
Added some header file documentation, and r
| |
487 | 574 |
488 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const | 575 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const |
489 { | 576 { |
490 // We simply remain at our intrinsic height. | 577 // We simply remain at our intrinsic height. |
491 computedValues.m_extent = logicalHeight; | 578 computedValues.m_extent = logicalHeight; |
492 computedValues.m_position = logicalTop; | 579 computedValues.m_position = logicalTop; |
493 } | 580 } |
494 | 581 |
495 void RenderMultiColumnFlowThread::updateLogicalWidth() | 582 void RenderMultiColumnFlowThread::updateLogicalWidth() |
496 { | 583 { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 } | 634 } |
548 | 635 |
549 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 636 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
550 { | 637 { |
551 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) | 638 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
552 return columnSet->pageLogicalHeight(); | 639 return columnSet->pageLogicalHeight(); |
553 return false; | 640 return false; |
554 } | 641 } |
555 | 642 |
556 } | 643 } |
OLD | NEW |