Bug 1322843 part 2 - Conditionally keep some floats in InlinePrefISizeData::ForceBreak. r=dbaron

This patch makes ForceBreak() partially clear floats according to the
break type of the coming block.

MozReview-Commit-ID: 71Gl9lBoTJ5

--HG--
extra : rebase_source : 5ca01565f607241df0c63a7cd64c35ac7ff7648f
This commit is contained in:
Xidorn Quan 2016-12-22 18:30:38 +11:00
Родитель 0f9ff65fce
Коммит 0fe4f86e06
3 изменённых файлов: 76 добавлений и 7 удалений

Просмотреть файл

@ -838,9 +838,14 @@ nsBlockFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
AutoNoisyIndenter lineindent(gNoisyIntrinsic);
#endif
if (line->IsBlock()) {
StyleClear breakType;
if (!data.mLineIsEmpty || BlockCanIntersectFloats(line->mFirstChild)) {
data.ForceBreak();
breakType = StyleClear::Both;
} else {
breakType = line->mFirstChild->
StyleDisplay()->PhysicalBreakType(data.mLineContainerWM);
}
data.ForceBreak(breakType);
data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
line->mFirstChild, nsLayoutUtils::PREF_ISIZE);
data.ForceBreak();

Просмотреть файл

@ -4512,9 +4512,17 @@ nsIFrame::InlineMinISizeData::OptionallyBreak(nscoord aHyphenWidth)
}
void
nsIFrame::InlinePrefISizeData::ForceBreak()
nsIFrame::InlinePrefISizeData::ForceBreak(StyleClear aBreakType)
{
if (mFloats.Length() != 0) {
MOZ_ASSERT(aBreakType == StyleClear::None ||
aBreakType == StyleClear::Both ||
aBreakType == StyleClear::Left ||
aBreakType == StyleClear::Right,
"Must be a physical break type");
// If this force break is not clearing any float, we can leave all the
// floats to the next force break.
if (mFloats.Length() != 0 && aBreakType != StyleClear::None) {
// preferred widths accumulated for floats that have already
// been cleared past
nscoord floats_done = 0,
@ -4522,11 +4530,12 @@ nsIFrame::InlinePrefISizeData::ForceBreak()
// been cleared past
floats_cur_left = 0,
floats_cur_right = 0;
const WritingMode wm = mLineContainerWM;
for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
const FloatInfo& floatInfo = mFloats[i];
const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
StyleClear breakType = floatDisp->PhysicalBreakType(mLineContainerWM);
StyleClear breakType = floatDisp->PhysicalBreakType(wm);
if (breakType == StyleClear::Left ||
breakType == StyleClear::Right ||
breakType == StyleClear::Both) {
@ -4543,7 +4552,7 @@ nsIFrame::InlinePrefISizeData::ForceBreak()
}
}
StyleFloat floatStyle = floatDisp->PhysicalFloats(mLineContainerWM);
StyleFloat floatStyle = floatDisp->PhysicalFloats(wm);
nscoord& floats_cur =
floatStyle == StyleFloat::Left ? floats_cur_left : floats_cur_right;
nscoord floatWidth = floatInfo.Width();
@ -4560,7 +4569,44 @@ nsIFrame::InlinePrefISizeData::ForceBreak()
mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, floats_done);
if (aBreakType == StyleClear::Both) {
mFloats.Clear();
} else {
// If the break type does not clear all floats, it means there may
// be some floats whose isize should contribute to the intrinsic
// isize of the next line. The code here scans the current mFloats
// and keeps floats which are not cleared by this break. Note that
// floats may be cleared directly or indirectly. See below.
nsTArray<FloatInfo> newFloats;
MOZ_ASSERT(aBreakType == StyleClear::Left ||
aBreakType == StyleClear::Right,
"Other values should have been handled in other branches");
StyleFloat clearFloatType =
aBreakType == StyleClear::Left ? StyleFloat::Left : StyleFloat::Right;
// Iterate the array in reverse so that we can stop when there are
// no longer any floats we need to keep. See below.
for (FloatInfo& floatInfo : Reversed(mFloats)) {
const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
if (floatDisp->PhysicalFloats(wm) != clearFloatType) {
newFloats.AppendElement(floatInfo);
} else {
// This is a float on the side that this break directly clears
// which means we're not keeping it in mFloats. However, if
// this float clears floats on the opposite side (via a value
// of either 'both' or one of 'left'/'right'), any remaining
// (earlier) floats on that side would be indirectly cleared
// as well. Thus, we should break out of this loop and stop
// considering earlier floats to be kept in mFloats.
StyleClear floatBreakType = floatDisp->PhysicalBreakType(wm);
if (floatBreakType != aBreakType &&
floatBreakType != StyleClear::None) {
break;
}
}
}
newFloats.Reverse();
mFloats = Move(newFloats);
}
}
mCurrentLine =

Просмотреть файл

@ -2020,11 +2020,29 @@ public:
};
struct InlinePrefISizeData : public InlineIntrinsicISizeData {
typedef mozilla::StyleClear StyleClear;
InlinePrefISizeData()
: mLineIsEmpty(true)
{}
void ForceBreak();
/**
* Finish the current line and start a new line.
*
* @param aBreakType controls whether isize of floats are considered
* and what floats are kept for the next line:
* * |None| skips handling floats, which means no floats are
* removed, and isizes of floats are not considered either.
* * |Both| takes floats into consideration when computing isize
* of the current line, and removes all floats after that.
* * |Left| and |Right| do the same as |Both| except that they only
* remove floats on the given side, and any floats on the other
* side that are prior to a float on the given side that has a
* 'clear' property that clears them.
* All other values of StyleClear must be converted to the four
* physical values above for this function.
*/
void ForceBreak(StyleClear aBreakType = StyleClear::Both);
// The default implementation for nsIFrame::AddInlinePrefISize.
void DefaultAddInlinePrefISize(nscoord aISize);