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

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: code review 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 // Go through the subtree that was just inserted and create column sets (nee ded by regular 444 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
445 // column content) and spanner placeholders (one needed by each spanner). 445 // This method ensures that the list of column sets and spanner placeholders reflects the
446 // multicol content after having inserted a descendant (or descendant subtre e). See the header
447 // file for more information. Go through the subtree that was just inserted and create column
448 // sets (needed by regular column content) and spanner placeholders (one nee ded by each spanner)
449 // where needed.
446 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) { 450 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) {
447 if (containingColumnSpannerPlaceholder(renderer)) 451 if (containingColumnSpannerPlaceholder(renderer))
448 continue; // Inside a column spanner. Nothing to do, then. 452 continue; // Inside a column spanner. Nothing to do, then.
449 if (descendantIsValidColumnSpanner(renderer)) { 453 if (descendantIsValidColumnSpanner(renderer)) {
450 // This renderer is a spanner, so it needs to establish a spanner pl aceholder. 454 // This renderer is a spanner, so it needs to establish a spanner pl aceholder.
451 createAndInsertSpannerPlaceholder(toRenderBox(renderer)); 455 RenderBox* insertBefore = 0;
456 RenderMultiColumnSet* setToSplit = 0;
457 if (nextRenderer) {
458 // The spanner is inserted before something. Figure out what thi s entails. If the
459 // next renderer is a spanner too, it means that we can simply i nsert a new spanner
460 // placeholder in front of its placeholder.
461 insertBefore = nextRenderer->spannerPlaceholder();
462 if (!insertBefore) {
463 // The next renderer isn't a spanner; it's regular column co ntent. Examine what
464 // comes right before us in the flow thread, then.
465 RenderObject* previousRenderer = renderer->previousInPreOrde r(this);
466 if (!previousRenderer || previousRenderer == this) {
467 // The spanner is inserted as the first child of the mul ticol container,
468 // which means that we simply insert a new spanner place holder at the
469 // beginning.
470 insertBefore = firstMultiColumnBox();
471 } else if (RenderMultiColumnSpannerPlaceholder* previousPlac eholder = containingColumnSpannerPlaceholder(previousRenderer)) {
472 // Before us is another spanner. We belong right after i t then.
473 insertBefore = previousPlaceholder->nextSiblingMultiColu mnBox();
474 } else {
475 // We're inside regular column content with both feet. F ind out which column
476 // set this is. It needs to be split it into two sets, s o that we can insert
477 // a new spanner placeholder between them.
478 setToSplit = findSetRendering(previousRenderer);
479 ASSERT(setToSplit == findSetRendering(nextRenderer));
480 setToSplit->setNeedsLayoutAndFullPaintInvalidation();
481 insertBefore = setToSplit->nextSiblingMultiColumnBox();
482 // We've found out which set that needs to be split. Now proceed to
483 // inserting the spanner placeholder, and then insert a second column set.
484 }
485 }
486 ASSERT(setToSplit || insertBefore);
487 }
488 createAndInsertSpannerPlaceholder(toRenderBox(renderer), insertBefor e);
489 if (setToSplit)
490 createAndInsertMultiColumnSet(insertBefore);
452 continue; 491 continue;
453 } 492 }
454 // This renderer is regular column content (i.e. not a spanner). Create a set if necessary. 493 // This renderer is regular column content (i.e. not a spanner). Create a set if necessary.
455 RenderBox* lastColumnBox = lastMultiColumnBox(); 494 if (nextRenderer) {
456 if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet()) 495 if (RenderMultiColumnSpannerPlaceholder* placeholder = nextRenderer- >spannerPlaceholder()) {
457 createAndInsertMultiColumnSet(); 496 // If inserted right before a spanner, we need to make sure that there's a set for us there.
497 RenderBox* previous = placeholder->previousSiblingMultiColumnBox ();
498 if (!previous || !previous->isRenderMultiColumnSet())
499 createAndInsertMultiColumnSet(placeholder);
500 } else {
501 // Otherwise, since |nextRenderer| isn't a spanner, it has to me an that there's
502 // already a set for that content. We can use it for this render er too.
503 ASSERT(findSetRendering(nextRenderer));
504 ASSERT(findSetRendering(renderer) == findSetRendering(nextRender er));
505 }
506 } else {
507 // Inserting at the end. Then we just need to make sure that there's a column set at the end.
508 RenderBox* lastColumnBox = lastMultiColumnBox();
509 if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet())
510 createAndInsertMultiColumnSet();
511 }
458 } 512 }
459 } 513 }
460 514
461 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant) 515 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant)
462 { 516 {
517 // This method ensures that the list of column sets and spanner placeholders reflects the
518 // multicol content that we'll be left with after removal of a descendant (o r descendant
519 // subtree). See the header file for more information. Removing content may mean that we need to
520 // remove column sets and/or spanner placeholders.
463 if (m_isBeingEvacuated) 521 if (m_isBeingEvacuated)
464 return; 522 return;
523 bool hadContainingPlaceholder = containingColumnSpannerPlaceholder(descendan t);
465 RenderObject* next; 524 RenderObject* next;
466 // Remove spanner placeholders that are no longer needed, and merge column s ets around them. 525 // Remove spanner placeholders that are no longer needed, and merge column s ets around them.
467 for (RenderObject* renderer = descendant; renderer; renderer = next) { 526 for (RenderObject* renderer = descendant; renderer; renderer = next) {
468 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlac eholder(); 527 RenderMultiColumnSpannerPlaceholder* placeholder = renderer->spannerPlac eholder();
469 if (!placeholder) { 528 if (!placeholder) {
470 next = renderer->nextInPreOrder(descendant); 529 next = renderer->nextInPreOrder(descendant);
471 continue; 530 continue;
472 } 531 }
473 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us. 532 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us.
474 if (RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox()) { 533 if (RenderBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox()) {
475 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColu mnBox(); 534 RenderBox* previousColumnBox = placeholder->previousSiblingMultiColu mnBox();
476 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet() 535 if (nextColumnBox && nextColumnBox->isRenderMultiColumnSet()
477 && previousColumnBox && previousColumnBox->isRenderMultiColumnSe t()) { 536 && previousColumnBox && previousColumnBox->isRenderMultiColumnSe t()) {
478 // Need to merge two column sets. 537 // Need to merge two column sets.
479 nextColumnBox->destroy(); 538 nextColumnBox->destroy();
480 previousColumnBox->setNeedsLayout(); 539 previousColumnBox->setNeedsLayout();
481 invalidateRegions(); 540 invalidateRegions();
482 } 541 }
483 } 542 }
484 placeholder->destroy(); 543 placeholder->destroy();
485 } 544 }
545 if (hadContainingPlaceholder)
546 return; // We're only removing a spanner (or something inside one), whic h means that no column content will be removed.
547
548 // Column content will be removed. Does this mean that we should destroy a c olumn set?
549 RenderMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = 0;
550 RenderObject* previousRenderer = descendant->previousInPreOrder(this);
551 if (previousRenderer && previousRenderer != this) {
552 adjacentPreviousSpannerPlaceholder = containingColumnSpannerPlaceholder( previousRenderer);
553 if (!adjacentPreviousSpannerPlaceholder)
554 return; // Preceded by column content. Set still needed.
555 }
556 RenderMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = 0;
557 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
558 if (nextRenderer) {
559 adjacentNextSpannerPlaceholder = containingColumnSpannerPlaceholder(next Renderer);
560 if (!adjacentNextSpannerPlaceholder)
561 return; // Followed by column content. Set still needed.
562 }
563 // We have now determined that, with the removal of |descendant|, we should remove a column
564 // set. Locate it and remove it. Do it without involving findSetRendering(), as that might be
565 // very slow. Deduce the right set from the spanner placeholders that we've already found.
566 RenderMultiColumnSet* columnSetToRemove;
567 if (adjacentNextSpannerPlaceholder) {
568 columnSetToRemove = toRenderMultiColumnSet(adjacentNextSpannerPlaceholde r->previousSiblingMultiColumnBox());
569 ASSERT(!adjacentPreviousSpannerPlaceholder || columnSetToRemove == adjac entPreviousSpannerPlaceholder->nextSiblingMultiColumnBox());
570 } else if (adjacentPreviousSpannerPlaceholder) {
571 columnSetToRemove = toRenderMultiColumnSet(adjacentPreviousSpannerPlaceh older->nextSiblingMultiColumnBox());
572 } else {
573 // If there were no adjacent spanners, it has to mean that there's only one column set,
574 // since it's only spanners that may cause creation of multiple sets.
575 columnSetToRemove = firstMultiColumnSet();
576 ASSERT(columnSetToRemove);
577 ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet());
578 }
579 ASSERT(columnSetToRemove);
580 columnSetToRemove->destroy();
486 } 581 }
487 582
488 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const 583 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
489 { 584 {
490 // We simply remain at our intrinsic height. 585 // We simply remain at our intrinsic height.
491 computedValues.m_extent = logicalHeight; 586 computedValues.m_extent = logicalHeight;
492 computedValues.m_position = logicalTop; 587 computedValues.m_position = logicalTop;
493 } 588 }
494 589
495 void RenderMultiColumnFlowThread::updateLogicalWidth() 590 void RenderMultiColumnFlowThread::updateLogicalWidth()
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 } 642 }
548 643
549 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const 644 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const
550 { 645 {
551 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) 646 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet())
552 return columnSet->pageLogicalHeight(); 647 return columnSet->pageLogicalHeight();
553 return false; 648 return false;
554 } 649 }
555 650
556 } 651 }
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderMultiColumnFlowThread.h ('k') | Source/core/rendering/RenderMultiColumnFlowThreadTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698