Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: Source/core/rendering/RenderMultiColumnFlowThread.cpp

Issue 869583002: [New Multicolumn] Support dynamic insertion and removal of multicol content. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698