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 // 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 Loading... |
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 } |
OLD | NEW |