OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google 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 are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 child.markForPaginationRelayoutIfNeeded(layoutScope); | 670 child.markForPaginationRelayoutIfNeeded(layoutScope); |
671 } | 671 } |
672 } | 672 } |
673 | 673 |
674 if (!child.needsLayout()) | 674 if (!child.needsLayout()) |
675 return false; | 675 return false; |
676 child.layout(); | 676 child.layout(); |
677 return true; | 677 return true; |
678 } | 678 } |
679 | 679 |
680 bool LayoutBlockFlow::insertForcedBreakBeforeChildIfNeeded(LayoutBox& child, Blo
ckChildrenLayoutInfo& layoutInfo) | 680 void LayoutBlockFlow::insertForcedBreakBeforeChildIfNeeded(LayoutBox& child, Blo
ckChildrenLayoutInfo& layoutInfo) |
681 { | 681 { |
682 if (layoutInfo.isAtFirstInFlowChild()) { | 682 if (layoutInfo.isAtFirstInFlowChild()) { |
683 // There's no class A break point before the first child (only *between*
siblings), so | 683 // There's no class A break point before the first child (only *between*
siblings), so |
684 // steal its break value and join it with what we already have here. | 684 // steal its break value and join it with what we already have here. |
685 setBreakBefore(joinFragmentainerBreakValues(breakBefore(), child.breakBe
fore())); | 685 setBreakBefore(joinFragmentainerBreakValues(breakBefore(), child.breakBe
fore())); |
686 return false; | 686 return; |
687 } | 687 } |
688 | 688 |
689 // Figure out if a forced break should be inserted in front of the child. If
we insert a forced | 689 // Figure out if a forced break should be inserted in front of the child. If
we insert a forced |
690 // break, the margins on this child may not collapse with those preceding th
e break. | 690 // break, the margins on this child may not collapse with those preceding th
e break. |
691 EBreak classABreakPointValue = child.classABreakPointValue(layoutInfo.previo
usBreakAfterValue()); | 691 EBreak classABreakPointValue = child.classABreakPointValue(layoutInfo.previo
usBreakAfterValue()); |
692 if (isForcedFragmentainerBreakValue(classABreakPointValue)) { | 692 if (isForcedFragmentainerBreakValue(classABreakPointValue)) { |
693 layoutInfo.marginInfo().clearMargin(); | 693 layoutInfo.marginInfo().clearMargin(); |
694 LayoutUnit oldLogicalTop = logicalHeight(); | 694 LayoutUnit oldLogicalTop = logicalHeight(); |
695 LayoutUnit newLogicalTop = applyForcedBreak(oldLogicalTop, classABreakPo
intValue); | 695 LayoutUnit newLogicalTop = applyForcedBreak(oldLogicalTop, classABreakPo
intValue); |
696 setLogicalHeight(newLogicalTop); | 696 setLogicalHeight(newLogicalTop); |
697 LayoutUnit paginationStrut = newLogicalTop - oldLogicalTop; | 697 LayoutUnit paginationStrut = newLogicalTop - oldLogicalTop; |
698 child.setPaginationStrut(paginationStrut); | 698 child.setPaginationStrut(paginationStrut); |
699 return true; | |
700 } | 699 } |
701 return false; | |
702 } | 700 } |
703 | 701 |
704 void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, BlockChildrenLayoutInfo
& layoutInfo) | 702 void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, BlockChildrenLayoutInfo
& layoutInfo) |
705 { | 703 { |
706 MarginInfo& marginInfo = layoutInfo.marginInfo(); | 704 MarginInfo& marginInfo = layoutInfo.marginInfo(); |
707 LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayout
BlockFlow(&child) : nullptr; | 705 LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayout
BlockFlow(&child) : nullptr; |
708 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); | 706 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); |
709 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); | 707 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); |
710 | 708 |
711 // The child is a normal flow object. Compute the margins we will use for co
llapsing now. | 709 // The child is a normal flow object. Compute the margins we will use for co
llapsing now. |
(...skipping 18 matching lines...) Expand all Loading... |
730 | 728 |
731 // Cache if we are at the top of the block right now. | 729 // Cache if we are at the top of the block right now. |
732 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); | 730 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); |
733 bool childIsSelfCollapsing = child.isSelfCollapsingBlock(); | 731 bool childIsSelfCollapsing = child.isSelfCollapsingBlock(); |
734 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child); | 732 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child); |
735 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child); | 733 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child); |
736 bool paginated = view()->layoutState()->isPaginated(); | 734 bool paginated = view()->layoutState()->isPaginated(); |
737 | 735 |
738 // If there should be a forced break before the child, we need to insert it
before attempting | 736 // If there should be a forced break before the child, we need to insert it
before attempting |
739 // to collapse margins or apply clearance. | 737 // to collapse margins or apply clearance. |
740 bool forcedBreakWasInserted = paginated && insertForcedBreakBeforeChildIfNee
ded(child, layoutInfo); | 738 if (paginated) { |
| 739 // We will now insert the strut needed by any forced break. After this o
peration, we will |
| 740 // have calculated the offset where we can apply margin collapsing and c
learance. After |
| 741 // having applied those things, we'll be at the position where we can ho
nor requirements of |
| 742 // unbreakable content, which may extend the strut further. |
| 743 child.resetPaginationStrut(); |
| 744 insertForcedBreakBeforeChildIfNeeded(child, layoutInfo); |
| 745 } |
741 | 746 |
742 // Now determine the correct ypos based off examination of collapsing margin | 747 // Now determine the correct ypos based off examination of collapsing margin |
743 // values. | 748 // values. |
744 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo, childI
sSelfCollapsing, childDiscardMarginBefore, childDiscardMarginAfter); | 749 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo, childI
sSelfCollapsing, childDiscardMarginBefore, childDiscardMarginAfter); |
745 | 750 |
746 // Now check for clear. | 751 // Now check for clear. |
747 bool childDiscardMargin = childDiscardMarginBefore || childDiscardMarginAfte
r; | 752 bool childDiscardMargin = childDiscardMarginBefore || childDiscardMarginAfte
r; |
748 LayoutUnit newLogicalTop = clearFloatsIfNeeded(child, marginInfo, oldPosMarg
inBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing, chil
dDiscardMargin); | 753 LayoutUnit newLogicalTop = clearFloatsIfNeeded(child, marginInfo, oldPosMarg
inBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing, chil
dDiscardMargin); |
749 | 754 |
750 // If there's a forced break in front of this child, its final position has
already been | 755 // If there's a forced break in front of this child, its final position has
already been |
751 // determined. Otherwise, see if there are other reasons for breaking before
it | 756 // determined. Otherwise, see if there are other reasons for breaking before
it |
752 // (break-inside:avoid, or not enough space for the first piece of child con
tent to fit in the | 757 // (break-inside:avoid, or not enough space for the first piece of child con
tent to fit in the |
753 // current fragmentainer), and adjust the position accordingly. | 758 // current fragmentainer), and adjust the position accordingly. |
754 if (paginated && !forcedBreakWasInserted) { | 759 if (paginated) { |
755 if (estimateWithoutPagination != newLogicalTop) { | 760 if (estimateWithoutPagination != newLogicalTop) { |
756 // We got a new position due to clearance or margin collapsing. Befo
re we attempt to | 761 // We got a new position due to clearance or margin collapsing. Befo
re we attempt to |
757 // paginate (which may result in the position changing again), let's
try again at the | 762 // paginate (which may result in the position changing again), let's
try again at the |
758 // new position (since a new position may result in a new logical he
ight). | 763 // new position (since a new position may result in a new logical he
ight). |
759 positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo); | 764 positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo); |
760 } | 765 } |
761 | 766 |
| 767 // We have now applied forced breaks, margin collapsing and clearance, a
nd we're at the |
| 768 // position where we can honor requirements of unbreakable content. |
762 newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, layo
utInfo, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop); | 769 newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, layo
utInfo, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop); |
763 } | 770 } |
764 | 771 |
765 // Clearance, margin collapsing or pagination may have given us a new logica
l top, in which | 772 // Clearance, margin collapsing or pagination may have given us a new logica
l top, in which |
766 // case we may have to reposition and possibly relayout as well. If we deter
mined during child | 773 // case we may have to reposition and possibly relayout as well. If we deter
mined during child |
767 // layout that we need to insert a break to honor widows, we also need to re
layout. | 774 // layout that we need to insert a break to honor widows, we also need to re
layout. |
768 if (newLogicalTop != logicalTopEstimate | 775 if (newLogicalTop != logicalTopEstimate |
769 || child.needsLayout() | 776 || child.needsLayout() |
770 || (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBre
akAtLineToAvoidWidow())) { | 777 || (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBre
akAtLineToAvoidWidow())) { |
771 positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo); | 778 positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
814 } | 821 } |
815 | 822 |
816 if (child.isLayoutMultiColumnSpannerPlaceholder()) { | 823 if (child.isLayoutMultiColumnSpannerPlaceholder()) { |
817 // The actual column-span:all element is positioned by this placeholder
child. | 824 // The actual column-span:all element is positioned by this placeholder
child. |
818 positionSpannerDescendant(toLayoutMultiColumnSpannerPlaceholder(child)); | 825 positionSpannerDescendant(toLayoutMultiColumnSpannerPlaceholder(child)); |
819 } | 826 } |
820 } | 827 } |
821 | 828 |
822 LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop,
LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo, bool atBeforeSideOfBlock
) | 829 LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop,
LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo, bool atBeforeSideOfBlock
) |
823 { | 830 { |
824 // Forced breaks trumps unforced ones, and if we have a forced break, we sho
uldn't even be here. | |
825 ASSERT(layoutInfo.isAtFirstInFlowChild() || !isForcedFragmentainerBreakValue
(child.classABreakPointValue(layoutInfo.previousBreakAfterValue()))); | |
826 | |
827 LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockF
low(&child) : 0; | 831 LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockF
low(&child) : 0; |
828 | 832 |
829 // See if we need a soft (unforced) break in front of this child, and set th
e pagination strut | 833 // See if we need a soft (unforced) break in front of this child, and set th
e pagination strut |
830 // in that case. An unforced break may come from two sources: | 834 // in that case. An unforced break may come from two sources: |
831 // 1. The first piece of content inside the child doesn't fit in the current
page or column | 835 // 1. The first piece of content inside the child doesn't fit in the current
page or column |
832 // 2. The child itself has breaking restrictions (break-inside:avoid, replac
ed content, etc.) | 836 // 2. The child itself has breaking restrictions (break-inside:avoid, replac
ed content, etc.) |
833 // and doesn't fully fit in the current page or column. | 837 // and doesn't fully fit in the current page or column. |
834 // | 838 // |
835 // No matter which source, if we need to insert a strut, it should always ta
ke us to the exact | 839 // No matter which source, if we need to insert a strut, it should always ta
ke us to the exact |
836 // top of a page or column further ahead, or be zero. | 840 // top of a page or column further ahead, or be zero. |
837 | 841 |
838 // We're now going to calculate the child's final pagination strut. We may e
nd up propagating | |
839 // it to its containing block (|this|), so reset it first. | |
840 child.resetPaginationStrut(); | |
841 | |
842 // The first piece of content inside the child may have set a strut during l
ayout. Currently, | 842 // The first piece of content inside the child may have set a strut during l
ayout. Currently, |
843 // only block flows support strut propagation, but this may (and should) cha
nge in the future. | 843 // only block flows support strut propagation, but this may (and should) cha
nge in the future. |
844 // See crbug.com/539873 | 844 // See crbug.com/539873 |
845 LayoutUnit strutFromContent = childBlockFlow ? childBlockFlow->paginationStr
utPropagatedFromChild() : LayoutUnit(); | 845 LayoutUnit strutFromContent = childBlockFlow ? childBlockFlow->paginationStr
utPropagatedFromChild() : LayoutUnit(); |
846 LayoutUnit logicalTopWithContentStrut = logicalTop + strutFromContent; | 846 LayoutUnit logicalTopWithContentStrut = logicalTop + strutFromContent; |
847 | 847 |
848 // For replaced elements and scrolled elements, we want to shift them to the
next page if they don't fit on the current one. | 848 // For replaced elements and scrolled elements, we want to shift them to the
next page if they don't fit on the current one. |
849 LayoutUnit logicalTopAfterUnsplittable = adjustForUnsplittableChild(child, l
ogicalTop); | 849 LayoutUnit logicalTopAfterUnsplittable = adjustForUnsplittableChild(child, l
ogicalTop); |
850 | 850 |
851 // Pick the largest offset. Tall unsplittable content may take us to a page
or column further | 851 // Pick the largest offset. Tall unsplittable content may take us to a page
or column further |
852 // ahead than the next one. | 852 // ahead than the next one. |
853 LayoutUnit logicalTopAfterPagination = std::max(logicalTopWithContentStrut,
logicalTopAfterUnsplittable); | 853 LayoutUnit logicalTopAfterPagination = std::max(logicalTopWithContentStrut,
logicalTopAfterUnsplittable); |
854 LayoutUnit newLogicalTop = logicalTop; | 854 LayoutUnit newLogicalTop = logicalTop; |
855 if (LayoutUnit paginationStrut = logicalTopAfterPagination - logicalTop) { | 855 |
| 856 // Forced breaks may already have caused a strut, and this needs to be added
together with |
| 857 // any strut detected here in this method. |
| 858 LayoutUnit previousStrut = child.paginationStrut(); |
| 859 |
| 860 if (LayoutUnit paginationStrut = logicalTopAfterPagination - logicalTop + pr
eviousStrut) { |
856 ASSERT(paginationStrut > 0); | 861 ASSERT(paginationStrut > 0); |
857 // If we're not at the first in-flow child, there's a class A break poin
t before the child. If we *are* at the | 862 // If we're not at the first in-flow child, there's a class A break poin
t before the child. If we *are* at the |
858 // first in-flow child, but the child isn't flush with the content edge
of its container, due to e.g. clearance, | 863 // first in-flow child, but the child isn't flush with the content edge
of its container, due to e.g. clearance, |
859 // there's a class C break point before the child. Otherwise we should p
ropagate the strut to our parent block, | 864 // there's a class C break point before the child. Otherwise we should p
ropagate the strut to our parent block, |
860 // and attempt to break there instead. See https://drafts.csswg.org/css-
break/#possible-breaks | 865 // and attempt to break there instead. See https://drafts.csswg.org/css-
break/#possible-breaks |
861 if (layoutInfo.isAtFirstInFlowChild() && atBeforeSideOfBlock && allowsPa
ginationStrut()) { | 866 if (layoutInfo.isAtFirstInFlowChild() && atBeforeSideOfBlock && allowsPa
ginationStrut()) { |
862 // FIXME: Should really check if we're exceeding the page height bef
ore propagating the strut, but we don't | 867 // FIXME: Should really check if we're exceeding the page height bef
ore propagating the strut, but we don't |
863 // have all the information to do so (the strut only has the remaini
ng amount to push). Gecko gets this wrong too | 868 // have all the information to do so (the strut only has the remaini
ng amount to push). Gecko gets this wrong too |
864 // and pushes to the next page anyway, so not too concerned about it
. | 869 // and pushes to the next page anyway, so not too concerned about it
. |
865 paginationStrut += logicalTop + marginBeforeIfFloating(); | 870 paginationStrut += logicalTop + marginBeforeIfFloating(); |
866 setPaginationStrutPropagatedFromChild(paginationStrut); | 871 setPaginationStrutPropagatedFromChild(paginationStrut); |
| 872 child.resetPaginationStrut(); |
867 if (childBlockFlow) | 873 if (childBlockFlow) |
868 childBlockFlow->setPaginationStrutPropagatedFromChild(LayoutUnit
()); | 874 childBlockFlow->setPaginationStrutPropagatedFromChild(LayoutUnit
()); |
869 } else { | 875 } else { |
870 child.setPaginationStrut(paginationStrut); | 876 child.setPaginationStrut(paginationStrut); |
871 newLogicalTop += paginationStrut; | 877 // |previousStrut| was already baked into the logical top, so don't
add it again. |
| 878 newLogicalTop += paginationStrut - previousStrut; |
872 } | 879 } |
873 } | 880 } |
874 | 881 |
875 // Similar to how we apply clearance. Go ahead and boost height() to be the
place where we're going to position the child. | 882 // Similar to how we apply clearance. Go ahead and boost height() to be the
place where we're going to position the child. |
876 setLogicalHeight(logicalHeight() + (newLogicalTop - logicalTop)); | 883 setLogicalHeight(logicalHeight() + (newLogicalTop - logicalTop)); |
877 | 884 |
878 // Return the final adjusted logical top. | 885 // Return the final adjusted logical top. |
879 return newLogicalTop; | 886 return newLogicalTop; |
880 } | 887 } |
881 | 888 |
(...skipping 2878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3760 | 3767 |
3761 return LayoutBlock::invalidatePaintIfNeeded(paintInvalidationState); | 3768 return LayoutBlock::invalidatePaintIfNeeded(paintInvalidationState); |
3762 } | 3769 } |
3763 | 3770 |
3764 void LayoutBlockFlow::invalidateDisplayItemClients(PaintInvalidationReason inval
idationReason) const | 3771 void LayoutBlockFlow::invalidateDisplayItemClients(PaintInvalidationReason inval
idationReason) const |
3765 { | 3772 { |
3766 BlockFlowPaintInvalidator(*this).invalidateDisplayItemClients(invalidationRe
ason); | 3773 BlockFlowPaintInvalidator(*this).invalidateDisplayItemClients(invalidationRe
ason); |
3767 } | 3774 } |
3768 | 3775 |
3769 } // namespace blink | 3776 } // namespace blink |
OLD | NEW |