From 22851ce36d97fca5a4768f3c49a4fff6cebd320a Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 28 Sep 2019 23:16:55 -0400 Subject: Issue #1233 - Part 1: Fix grid overflow and rendering issues by improving Layout CSS-Grid API List of relevant patches applied: 1425599 part 1 - [css-grid] Change the track sizing algorithm for spanning items so that it accumulates individual item contributions to the plan by max() rather than incrementing the planned size directly. Also, fix a bug when copying back the planned limits after updating it for the first span group. It should only copy back track sizes that were actaully spanned by those items, other content-sized tracks' limits should remain at "infinity". 1425599 part 2 - [css-grid] Factor out the min-sizing parts of the track sizing for spanned items to a templated method (idempotent change). 1425599 part 3 - [css-grid] Factor out most of the max-sizing parts of the track sizing for spanned items to a templated method (idempotent change). 1425599 part 4 - [css-grid] Factor out the starting base/limit size to a templated method (idempotent change). 1425599 part 5 - [css-grid] Make CollectGrowable a templated method so that it works with either base/limit sizes (idempotent change). 1425599 part 6 - [css-grid] Make the size distribution methods templated with the intent of merging them in a later patch (idempotent change). This patch also introduces an eInfinitelyGrowable bit to help get rid of the 'limits' temporary track sizes in the next patch. 1425599 part 7 - [css-grid] Remove the 'limits' copy of track sizes since they are no longer needed (idempotent change). 1425599 part 8 - [css-grid] Factor out the fit-content clamping function from DistributeToTrackLimits and pass it as a param instead (idempotent change). 1425599 part 9 - [css-grid] Merge DistributeToTrackLimits/Bases (idempotent change). 1425599 part 10 - [css-grid] Make MarkExcludedTracks a static method since it doesn't use 'this' (idempotent change). 1425599 part 11 - [css-grid] Hoist the marking of excluded tracks out from GrowSelectedTracksUnlimited to a separate method (idempotent change). 1425599 part 12 - [css-grid] Merge CopyPlanToBase/Limits into a templated method instead (idempotent change). 1425599 part 13 - [css-grid] Merge Grow[Base|Limits]ForSpanningItems into a templated method instead (idempotent change). 1425599 part 14 - [css-grid] Use iterators instead of an array + start/end index for the item data (idempotent change). 1425599 part 16 - [css-grid] Make SizeContributionForPhase a template. 1425599 - [css-grid] Follow-up bustage fix for stupid compiler warnings. 1378481 - Assign 'roundingError' in the default branch too, to avoid a maybe-uninitialized compiler warning. 1423292 - [css-grid] Add a couple of ItemState bits to Dump(), and make an ItemState assertion stricter (DEBUG-only changes). 1373678 Part 1: Reduce grid line numbers by count of leading implicit lines, minimum 0. 1416350 - Part 1: Correctly account for removed 'auto-fit' tracks also when there are leading implicit tracks. 1416350 - Part 2: Correct logic for Grid API line numbering with leading implicit tracks. 1418727 part 1 - [css-grid] Introduce StateBitsForRange() that collects the union of the state bits for a range of tracks (idempotent change). 1418727 part 2 - [css-grid] Require that an item spans at least one track with an 'auto' min sizing function for Automatic Minimum Size to apply. --- layout/generic/nsGridContainerFrame.cpp | 661 ++++++++++++++++++-------------- 1 file changed, 383 insertions(+), 278 deletions(-) (limited to 'layout') diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 3a2d5ad1d..59f58f268 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -198,7 +198,7 @@ struct nsGridContainerFrame::TrackSize eMaxContentMinSizing = 0x4, eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing, eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing, - // 0x8 is unused, feel free to take it! + eModified = 0x8, eAutoMaxSizing = 0x10, eMinContentMaxSizing = 0x20, eMaxContentMaxSizing = 0x40, @@ -211,6 +211,7 @@ struct nsGridContainerFrame::TrackSize eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2, eBreakBefore = 0x800, eFitContent = 0x1000, + eInfinitelyGrowable = 0x2000, }; StateBits Initialize(nscoord aPercentageBasis, @@ -856,6 +857,8 @@ struct nsGridContainerFrame::GridItemInfo // Return true if we should apply Automatic Minimum Size to this item. // https://drafts.csswg.org/css-grid/#min-size-auto + // @note the caller should also check that the item spans at least one track + // that has a min track sizing function that is 'auto' before applying it. bool ShouldApplyAutoMinSize(WritingMode aContainerWM, LogicalAxis aContainerAxis, nscoord aPercentageBasis) const @@ -915,6 +918,12 @@ nsGridContainerFrame::GridItemInfo::Dump() const if (state & ItemState::eIsFlexing) { printf("flexing "); } + if (state & ItemState::eApplyAutoMinSize) { + printf("auto-min-size "); + } + if (state & ItemState::eClampMarginBoxMinSize) { + printf("clamp "); + } if (state & ItemState::eFirstBaseline) { printf("first baseline %s-alignment ", (state & ItemState::eSelfBaseline) ? "self" : "content"); @@ -1091,6 +1100,7 @@ private: const nsTArray& mRepeatAutoLineNameListBefore; const nsTArray& mRepeatAutoLineNameListAfter; // The index of the repeat(auto-fill/fit) track, or zero if there is none. + // Relative to mExplicitGridOffset (repeat tracks are explicit by definition). const uint32_t mRepeatAutoStart; // The (hypothetical) index of the last such repeat() track. const uint32_t mRepeatAutoEnd; @@ -1101,6 +1111,7 @@ private: // generates one track (making mRepeatEndDelta == 0). const uint32_t mTemplateLinesEnd; // True if there is a specified repeat(auto-fill/fit) track. + // Indexed relative to mExplicitGridOffset + mRepeatAutoStart. const bool mHasRepeatAuto; }; @@ -1340,15 +1351,9 @@ struct nsGridContainerFrame::Tracks nscoord aContentBoxSize); /** - * Return true if aRange spans at least one track with an intrinsic sizing - * function and does not span any tracks with a max-sizing function. - * @param aRange the span of tracks to check - * @param aState will be set to the union of the state bits of all the spanned - * tracks, unless a flex track is found - then it only contains - * the union of the tracks up to and including the flex track. + * Return the union of the state bits for the tracks in aRange. */ - bool HasIntrinsicButNoFlexSizingInRange(const LineRange& aRange, - TrackSize::StateBits* aState) const; + TrackSize::StateBits StateBitsForRange(const LineRange& aRange) const; // Some data we collect for aligning baseline-aligned items. struct ItemBaselineData @@ -1383,6 +1388,62 @@ struct nsGridContainerFrame::Tracks */ void AlignBaselineSubtree(const GridItemInfo& aGridItem) const; + enum class TrackSizingPhase + { + eIntrinsicMinimums, + eContentBasedMinimums, + eMaxContentMinimums, + eIntrinsicMaximums, + eMaxContentMaximums, + }; + + // Some data we collect on each item for Step 2 of the Track Sizing Algorithm + // in ResolveIntrinsicSize below. + struct Step2ItemData final + { + uint32_t mSpan; + TrackSize::StateBits mState; + LineRange mLineRange; + nscoord mMinSize; + nscoord mMinContentContribution; + nscoord mMaxContentContribution; + nsIFrame* mFrame; + static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b) + { + return a.mSpan < b.mSpan; + } + + template + nscoord SizeContributionForPhase() const + { + switch (phase) { + case TrackSizingPhase::eIntrinsicMinimums: + case TrackSizingPhase::eIntrinsicMaximums: + return mMinSize; + case TrackSizingPhase::eContentBasedMinimums: + return mMinContentContribution; + case TrackSizingPhase::eMaxContentMinimums: + case TrackSizingPhase::eMaxContentMaximums: + return mMaxContentContribution; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase"); + } + }; + + using FitContentClamper = + function; + + // Helper method for ResolveIntrinsicSize. + template + bool GrowSizeForSpanningItems(nsTArray::iterator aIter, + const nsTArray::iterator aEnd, + nsTArray& aTracks, + nsTArray& aPlan, + nsTArray& aItemPlan, + TrackSize::StateBits aSelector, + const FitContentClamper& aClamper = nullptr, + bool aNeedInfinitelyGrowableFlag = false); + /** * Resolve Intrinsic Track Sizes. * http://dev.w3.org/csswg/css-grid/#algo-content @@ -1405,66 +1466,117 @@ struct nsGridContainerFrame::Tracks SizingConstraint aConstraint, const LineRange& aRange, const GridItemInfo& aGridItem); + + // Helper method that returns the track size to use in §11.5.1.2 + // https://drafts.csswg.org/css-grid/#extra-space + template static + nscoord StartSizeInDistribution(const TrackSize& aSize) + { + switch (phase) { + case TrackSizingPhase::eIntrinsicMinimums: + case TrackSizingPhase::eContentBasedMinimums: + case TrackSizingPhase::eMaxContentMinimums: + return aSize.mBase; + case TrackSizingPhase::eIntrinsicMaximums: + case TrackSizingPhase::eMaxContentMaximums: + if (aSize.mLimit == NS_UNCONSTRAINEDSIZE) { + return aSize.mBase; + } + return aSize.mLimit; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase"); + } + /** * Collect the tracks which are growable (matching aSelector) into * aGrowableTracks, and return the amount of space that can be used - * to grow those tracks. Specifically, we return aAvailableSpace minus - * the sum of mBase's (and corresponding grid gaps) in aPlan (clamped to 0) - * for the tracks in aRange, or zero when there are no growable tracks. - * @note aPlan[*].mBase represents a planned new base or limit. + * to grow those tracks. This method implements CSS Grid §11.5.1.2. + * https://drafts.csswg.org/css-grid/#extra-space */ - nscoord CollectGrowable(nscoord aAvailableSpace, - const nsTArray& aPlan, - const LineRange& aRange, - TrackSize::StateBits aSelector, - nsTArray& aGrowableTracks) const + template + nscoord CollectGrowable(nscoord aAvailableSpace, + const LineRange& aRange, + TrackSize::StateBits aSelector, + nsTArray& aGrowableTracks) const { MOZ_ASSERT(aAvailableSpace > 0, "why call me?"); nscoord space = aAvailableSpace - mGridGap * (aRange.Extent() - 1); const uint32_t start = aRange.mStart; const uint32_t end = aRange.mEnd; for (uint32_t i = start; i < end; ++i) { - const TrackSize& sz = aPlan[i]; - space -= sz.mBase; + const TrackSize& sz = mSizes[i]; + space -= StartSizeInDistribution(sz); if (space <= 0) { return 0; } - if ((sz.mState & aSelector) && !sz.IsFrozen()) { + if (sz.mState & aSelector) { aGrowableTracks.AppendElement(i); } } return aGrowableTracks.IsEmpty() ? 0 : space; } - void SetupGrowthPlan(nsTArray& aPlan, - const nsTArray& aTracks) const + template + void InitializeItemPlan(nsTArray& aItemPlan, + const nsTArray& aTracks) const { for (uint32_t track : aTracks) { - aPlan[track] = mSizes[track]; + auto& plan = aItemPlan[track]; + const TrackSize& sz = mSizes[track]; + plan.mBase = StartSizeInDistribution(sz); + bool unlimited = sz.mState & TrackSize::eInfinitelyGrowable; + plan.mLimit = unlimited ? NS_UNCONSTRAINEDSIZE : sz.mLimit; + plan.mState = sz.mState; } } - void CopyPlanToBase(const nsTArray& aPlan, - const nsTArray& aTracks) + template + void InitializePlan(nsTArray& aPlan) const { - for (uint32_t track : aTracks) { - MOZ_ASSERT(mSizes[track].mBase <= aPlan[track].mBase); - mSizes[track].mBase = aPlan[track].mBase; + for (size_t i = 0, len = aPlan.Length(); i < len; ++i) { + auto& plan = aPlan[i]; + const auto& sz = mSizes[i]; + plan.mBase = StartSizeInDistribution(sz); + MOZ_ASSERT(phase == TrackSizingPhase::eMaxContentMaximums || + !(sz.mState & TrackSize::eInfinitelyGrowable), + "forgot to reset the eInfinitelyGrowable bit?"); + plan.mState = sz.mState; } } - void CopyPlanToLimit(const nsTArray& aPlan, - const nsTArray& aTracks) + template + void CopyPlanToSize(const nsTArray& aPlan, + bool aNeedInfinitelyGrowableFlag = false) { - for (uint32_t track : aTracks) { - MOZ_ASSERT(mSizes[track].mLimit == NS_UNCONSTRAINEDSIZE || - mSizes[track].mLimit <= aPlan[track].mBase); - mSizes[track].mLimit = aPlan[track].mBase; + for (size_t i = 0, len = mSizes.Length(); i < len; ++i) { + const auto& plan = aPlan[i]; + MOZ_ASSERT(plan.mBase >= 0); + auto& sz = mSizes[i]; + switch (phase) { + case TrackSizingPhase::eIntrinsicMinimums: + case TrackSizingPhase::eContentBasedMinimums: + case TrackSizingPhase::eMaxContentMinimums: + sz.mBase = plan.mBase; + break; + case TrackSizingPhase::eIntrinsicMaximums: + if (plan.mState & TrackSize::eModified) { + if (sz.mLimit == NS_UNCONSTRAINEDSIZE && + aNeedInfinitelyGrowableFlag) { + sz.mState |= TrackSize::eInfinitelyGrowable; + } + sz.mLimit = plan.mBase; + } + break; + case TrackSizingPhase::eMaxContentMaximums: + if (plan.mState & TrackSize::eModified) { + sz.mLimit = plan.mBase; + } + sz.mState &= ~TrackSize::eInfinitelyGrowable; + break; + } } } - using FitContentClamper = - function; /** * Grow the planned size for tracks in aGrowableTracks up to their limit * and then freeze them (all aGrowableTracks must be unfrozen on entry). @@ -1524,12 +1636,13 @@ struct nsGridContainerFrame::Tracks * assumed that aPlan have no aSkipFlag set for tracks in aGrowableTracks * on entry to this method. */ - uint32_t MarkExcludedTracks(nsTArray& aPlan, - uint32_t aNumGrowable, - const nsTArray& aGrowableTracks, - TrackSize::StateBits aMinSizingSelector, - TrackSize::StateBits aMaxSizingSelector, - TrackSize::StateBits aSkipFlag) const + static uint32_t + MarkExcludedTracks(nsTArray& aPlan, + uint32_t aNumGrowable, + const nsTArray& aGrowableTracks, + TrackSize::StateBits aMinSizingSelector, + TrackSize::StateBits aMaxSizingSelector, + TrackSize::StateBits aSkipFlag) { bool foundOneSelected = false; bool foundOneGrowable = false; @@ -1559,41 +1672,60 @@ struct nsGridContainerFrame::Tracks } /** - * Increase the planned size for tracks in aGrowableTracks that match - * aSelector (or all tracks if aSelector is zero) beyond their limit. + * Mark all tracks in aGrowableTracks with an eSkipGrowUnlimited bit if + * they *shouldn't* grow unlimited in §11.5.1.2.3 "Distribute space beyond + * growth limits" https://drafts.csswg.org/css-grid/#extra-space + * Return the number of tracks that are still growable. + */ + template + static uint32_t + MarkExcludedTracks(nsTArray& aPlan, + const nsTArray& aGrowableTracks, + TrackSize::StateBits aSelector) + { + uint32_t numGrowable = aGrowableTracks.Length(); + if (phase == TrackSizingPhase::eIntrinsicMaximums || + phase == TrackSizingPhase::eMaxContentMaximums) { + // "when handling any intrinsic growth limit: all affected tracks" + return numGrowable; + } + MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) && + (aSelector & TrackSize::eMaxContentMinSizing), + "Should only get here for track sizing steps 2.1 to 2.3"); + // Note that eMaxContentMinSizing is always included. We do those first: + numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks, + TrackSize::eMaxContentMinSizing, + TrackSize::eMaxContentMaxSizing, + TrackSize::eSkipGrowUnlimited1); + // Now mark min-content/auto min-sizing tracks if requested. + auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing; + if (minOrAutoSelector) { + numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks, + minOrAutoSelector, + TrackSize::eIntrinsicMaxSizing, + TrackSize::eSkipGrowUnlimited2); + } + return numGrowable; + } + + /** + * Increase the planned size for tracks in aGrowableTracks that aren't + * marked with a eSkipGrowUnlimited flag beyond their limit. * This implements the "Distribute space beyond growth limits" step in * https://drafts.csswg.org/css-grid/#distribute-extra-space */ void GrowSelectedTracksUnlimited(nscoord aAvailableSpace, nsTArray& aPlan, const nsTArray& aGrowableTracks, - TrackSize::StateBits aSelector, + uint32_t aNumGrowable, FitContentClamper aFitContentClamper) const { - MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0); - uint32_t numGrowable = aGrowableTracks.Length(); - if (aSelector) { - MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) && - (aSelector & TrackSize::eMaxContentMinSizing), - "Should only get here for track sizing steps 2.1 to 2.3"); - // Note that eMaxContentMinSizing is always included. We do those first: - numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks, - TrackSize::eMaxContentMinSizing, - TrackSize::eMaxContentMaxSizing, - TrackSize::eSkipGrowUnlimited1); - // Now mark min-content/auto min-sizing tracks if requested. - auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing; - if (minOrAutoSelector) { - numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks, - minOrAutoSelector, - TrackSize::eIntrinsicMaxSizing, - TrackSize::eSkipGrowUnlimited2); - } - } + MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && + aNumGrowable <= aGrowableTracks.Length()); nscoord space = aAvailableSpace; DebugOnly didClamp = false; - while (numGrowable) { - nscoord spacePerTrack = std::max(space / numGrowable, 1); + while (aNumGrowable) { + nscoord spacePerTrack = std::max(space / aNumGrowable, 1); for (uint32_t track : aGrowableTracks) { TrackSize& sz = aPlan[track]; if (sz.mState & TrackSize::eSkipGrowUnlimited) { @@ -1609,7 +1741,7 @@ struct nsGridContainerFrame::Tracks delta = newBase - sz.mBase; MOZ_ASSERT(delta >= 0, "track size shouldn't shrink"); sz.mState |= TrackSize::eSkipGrowUnlimited1; - --numGrowable; + --aNumGrowable; } } sz.mBase = newBase; @@ -1628,46 +1760,30 @@ struct nsGridContainerFrame::Tracks * Distribute aAvailableSpace to the planned base size for aGrowableTracks * up to their limits, then distribute the remaining space beyond the limits. */ - void DistributeToTrackBases(nscoord aAvailableSpace, + template + void DistributeToTrackSizes(nscoord aAvailableSpace, nsTArray& aPlan, + nsTArray& aItemPlan, nsTArray& aGrowableTracks, - TrackSize::StateBits aSelector) + TrackSize::StateBits aSelector, + const FitContentClamper& aFitContentClamper) { - SetupGrowthPlan(aPlan, aGrowableTracks); - nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, nullptr); + InitializeItemPlan(aItemPlan, aGrowableTracks); + nscoord space = GrowTracksToLimit(aAvailableSpace, aItemPlan, aGrowableTracks, + aFitContentClamper); if (space > 0) { - GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector, nullptr); + uint32_t numGrowable = + MarkExcludedTracks(aItemPlan, aGrowableTracks, aSelector); + GrowSelectedTracksUnlimited(space, aItemPlan, aGrowableTracks, + numGrowable, aFitContentClamper); } - CopyPlanToBase(aPlan, aGrowableTracks); - } - - /** - * Distribute aAvailableSpace to the planned limits for aGrowableTracks. - */ - void DistributeToTrackLimits(nscoord aAvailableSpace, - nsTArray& aPlan, - nsTArray& aGrowableTracks, - const TrackSizingFunctions& aFunctions, - nscoord aPercentageBasis) - { - auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack, - nscoord aMinSize, - nscoord* aSize) { - nscoord fitContentLimit = - ::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis); - if (*aSize > fitContentLimit) { - *aSize = std::max(aMinSize, fitContentLimit); - return true; + for (uint32_t track : aGrowableTracks) { + nscoord& plannedSize = aPlan[track].mBase; + nscoord itemIncurredSize = aItemPlan[track].mBase; + if (plannedSize < itemIncurredSize) { + plannedSize = itemIncurredSize; } - return false; - }; - nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, - fitContentClamper); - if (space > 0) { - GrowSelectedTracksUnlimited(aAvailableSpace, aPlan, aGrowableTracks, - TrackSize::StateBits(0), fitContentClamper); } - CopyPlanToLimit(aPlan, aGrowableTracks); } /** @@ -3545,19 +3661,27 @@ nsGridContainerFrame::Grid::PlaceGridItems(GridReflowInput& aState, // Count empty 'auto-fit' tracks in the repeat() range. // |colAdjust| will have a count for each line in the grid of how many // tracks were empty between the start of the grid and that line. + + // Since this loop is concerned with just the repeat tracks, we + // iterate from 0..NumRepeatTracks() which is the natural range of + // mRemoveRepeatTracks. This means we have to add + // (mExplicitGridOffset + mRepeatAutoStart) to get a zero-based + // index for arrays like mCellMap and colAdjust. We'll then fill out + // the colAdjust array for all the remaining lines. Maybe> colAdjust; uint32_t numEmptyCols = 0; if (aState.mColFunctions.mHasRepeatAuto && !gridStyle->mGridTemplateColumns.mIsAutoFill && aState.mColFunctions.NumRepeatTracks() > 0) { - for (uint32_t col = aState.mColFunctions.mRepeatAutoStart, - endRepeat = aState.mColFunctions.mRepeatAutoEnd, - numColLines = mGridColEnd + 1; - col < numColLines; ++col) { + const uint32_t repeatStart = (aState.mColFunctions.mExplicitGridOffset + + aState.mColFunctions.mRepeatAutoStart); + const uint32_t numRepeats = aState.mColFunctions.NumRepeatTracks(); + const uint32_t numColLines = mGridColEnd + 1; + for (uint32_t i = 0; i < numRepeats; ++i) { if (numEmptyCols) { - (*colAdjust)[col] = numEmptyCols; + (*colAdjust)[repeatStart + i] = numEmptyCols; } - if (col < endRepeat && mCellMap.IsEmptyCol(col)) { + if (mCellMap.IsEmptyCol(repeatStart + i)) { ++numEmptyCols; if (colAdjust.isNothing()) { colAdjust.emplace(numColLines); @@ -3565,26 +3689,34 @@ nsGridContainerFrame::Grid::PlaceGridItems(GridReflowInput& aState, PodZero(colAdjust->Elements(), colAdjust->Length()); } - uint32_t repeatIndex = col - aState.mColFunctions.mRepeatAutoStart; - MOZ_ASSERT(aState.mColFunctions.mRemovedRepeatTracks.Length() > - repeatIndex); - aState.mColFunctions.mRemovedRepeatTracks[repeatIndex] = true; + aState.mColFunctions.mRemovedRepeatTracks[i] = true; + } + } + // Fill out the colAdjust array for all the columns after the + // repeats. + if (numEmptyCols) { + for (uint32_t col = repeatStart + numRepeats; + col < numColLines; ++col) { + (*colAdjust)[col] = numEmptyCols; } } } + + // Do similar work for the row tracks, with the same logic. Maybe> rowAdjust; uint32_t numEmptyRows = 0; if (aState.mRowFunctions.mHasRepeatAuto && !gridStyle->mGridTemplateRows.mIsAutoFill && aState.mRowFunctions.NumRepeatTracks() > 0) { - for (uint32_t row = aState.mRowFunctions.mRepeatAutoStart, - endRepeat = aState.mRowFunctions.mRepeatAutoEnd, - numRowLines = mGridRowEnd + 1; - row < numRowLines; ++row) { + const uint32_t repeatStart = (aState.mRowFunctions.mExplicitGridOffset + + aState.mRowFunctions.mRepeatAutoStart); + const uint32_t numRepeats = aState.mRowFunctions.NumRepeatTracks(); + const uint32_t numRowLines = mGridRowEnd + 1; + for (uint32_t i = 0; i < numRepeats; ++i) { if (numEmptyRows) { - (*rowAdjust)[row] = numEmptyRows; + (*rowAdjust)[repeatStart + i] = numEmptyRows; } - if (row < endRepeat && mCellMap.IsEmptyRow(row)) { + if (mCellMap.IsEmptyRow(repeatStart + i)) { ++numEmptyRows; if (rowAdjust.isNothing()) { rowAdjust.emplace(numRowLines); @@ -3592,10 +3724,13 @@ nsGridContainerFrame::Grid::PlaceGridItems(GridReflowInput& aState, PodZero(rowAdjust->Elements(), rowAdjust->Length()); } - uint32_t repeatIndex = row - aState.mRowFunctions.mRepeatAutoStart; - MOZ_ASSERT(aState.mRowFunctions.mRemovedRepeatTracks.Length() > - repeatIndex); - aState.mRowFunctions.mRemovedRepeatTracks[repeatIndex] = true; + aState.mRowFunctions.mRemovedRepeatTracks[i] = true; + } + } + if (numEmptyRows) { + for (uint32_t row = repeatStart + numRepeats; + row < numRowLines; ++row) { + (*rowAdjust)[row] = numEmptyRows; } } } @@ -3974,28 +4109,16 @@ nsGridContainerFrame::Tracks::CalculateSizes( } } -bool -nsGridContainerFrame::Tracks::HasIntrinsicButNoFlexSizingInRange( - const LineRange& aRange, - TrackSize::StateBits* aState) const +TrackSize::StateBits +nsGridContainerFrame::Tracks::StateBitsForRange(const LineRange& aRange) const { - MOZ_ASSERT(!aRange.IsAuto(), "must have a definite range"); + TrackSize::StateBits state = TrackSize::StateBits(0); const uint32_t start = aRange.mStart; const uint32_t end = aRange.mEnd; - const TrackSize::StateBits selector = - TrackSize::eIntrinsicMinSizing | TrackSize::eIntrinsicMaxSizing; - bool foundIntrinsic = false; for (uint32_t i = start; i < end; ++i) { - TrackSize::StateBits state = mSizes[i].mState; - *aState |= state; - if (state & TrackSize::eFlexMaxSizing) { - return false; - } - if (state & selector) { - foundIntrinsic = true; - } + state |= mSizes[i].mState; } - return foundIntrinsic; + return state; } bool @@ -4010,6 +4133,13 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1( CachedIntrinsicSizes cache; TrackSize& sz = mSizes[aRange.mStart]; WritingMode wm = aState.mWM; + + // Check if we need to apply "Automatic Minimum Size" and cache it. + if ((sz.mState & TrackSize::eAutoMinSizing) && + aGridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) { + aGridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize; + } + // Calculate data for "Automatic Minimum Size" clamping, if needed. bool needed = ((sz.mState & TrackSize::eIntrinsicMinSizing) || aConstraint == SizingConstraint::eNoConstraint) && @@ -4370,6 +4500,55 @@ nsGridContainerFrame::Tracks::AlignBaselineSubtree( } } +template +bool +nsGridContainerFrame::Tracks::GrowSizeForSpanningItems( + nsTArray::iterator aIter, + const nsTArray::iterator aIterEnd, + nsTArray& aTracks, + nsTArray& aPlan, + nsTArray& aItemPlan, + TrackSize::StateBits aSelector, + const FitContentClamper& aFitContentClamper, + bool aNeedInfinitelyGrowableFlag) +{ + constexpr bool isMaxSizingPhase = + phase == TrackSizingPhase::eIntrinsicMaximums || + phase == TrackSizingPhase::eMaxContentMaximums; + bool needToUpdateSizes = false; + InitializePlan(aPlan); + for (; aIter != aIterEnd; ++aIter) { + const Step2ItemData& item = *aIter; + if (!(item.mState & aSelector)) { + continue; + } + if (isMaxSizingPhase) { + for (auto j = item.mLineRange.mStart, end = item.mLineRange.mEnd; j < end; ++j) { + aPlan[j].mState |= TrackSize::eModified; + } + } + nscoord space = item.SizeContributionForPhase(); + if (space <= 0) { + continue; + } + aTracks.ClearAndRetainStorage(); + space = CollectGrowable(space, item.mLineRange, aSelector, + aTracks); + if (space > 0) { + DistributeToTrackSizes(space, aPlan, aItemPlan, aTracks, aSelector, + aFitContentClamper); + needToUpdateSizes = true; + } + } + if (isMaxSizingPhase) { + needToUpdateSizes = true; + } + if (needToUpdateSizes) { + CopyPlanToSize(aPlan, aNeedInfinitelyGrowableFlag); + } + return needToUpdateSizes; +} + void nsGridContainerFrame::Tracks::ResolveIntrinsicSize( GridReflowInput& aState, @@ -4379,21 +4558,6 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( nscoord aPercentageBasis, SizingConstraint aConstraint) { - // Some data we collect on each item for Step 2 of the algorithm below. - struct Step2ItemData - { - uint32_t mSpan; - TrackSize::StateBits mState; - LineRange mLineRange; - nscoord mMinSize; - nscoord mMinContentContribution; - nscoord mMaxContentContribution; - nsIFrame* mFrame; - static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b) - { - return a.mSpan < b.mSpan; - } - }; // Resolve Intrinsic Track Sizes // http://dev.w3.org/csswg/css-grid/#algo-content @@ -4418,12 +4582,10 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( for (; !iter.AtEnd(); iter.Next()) { auto& gridItem = aGridItems[iter.GridItemIndex()]; - // Check if we need to apply "Automatic Minimum Size" and cache it. - MOZ_ASSERT(!(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize), - "Why is eApplyAutoMinSize set already?"); - if (gridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) { - gridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize; - } + MOZ_ASSERT(!(gridItem.mState[mAxis] & + (ItemState::eApplyAutoMinSize | ItemState::eIsFlexing | + ItemState::eClampMarginBoxMinSize)), + "Why are any of these bits set already?"); const GridArea& area = gridItem.mArea; const LineRange& lineRange = area.*aRange; @@ -4435,8 +4597,17 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( gridItem.mState[mAxis] |= ItemState::eIsFlexing; } } else { - TrackSize::StateBits state = TrackSize::StateBits(0); - if (HasIntrinsicButNoFlexSizingInRange(lineRange, &state)) { + TrackSize::StateBits state = StateBitsForRange(lineRange); + + // Check if we need to apply "Automatic Minimum Size" and cache it. + if ((state & TrackSize::eAutoMinSizing) && + gridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) { + gridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize; + } + + if ((state & (TrackSize::eIntrinsicMinSizing | + TrackSize::eIntrinsicMaxSizing)) && + !(state & TrackSize::eFlexMaxSizing)) { // Collect data for Step 2. maxSpan = std::max(maxSpan, span); if (span >= stateBitsPerSpan.Length()) { @@ -4500,6 +4671,18 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( // Step 2. if (maxSpan) { + auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack, + nscoord aMinSize, + nscoord* aSize) + { + nscoord fitContentLimit = + ::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis); + if (*aSize > fitContentLimit) { + *aSize = std::max(aMinSize, fitContentLimit); + return true; + } + return false; + }; // Sort the collected items on span length, shortest first. std::stable_sort(step2Items.begin(), step2Items.end(), Step2ItemData::IsSpanLessThan); @@ -4507,85 +4690,44 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( nsTArray tracks(maxSpan); nsTArray plan(mSizes.Length()); plan.SetLength(mSizes.Length()); - for (uint32_t i = 0, len = step2Items.Length(); i < len; ) { - // Start / end index for items of the same span length: - const uint32_t spanGroupStartIndex = i; - uint32_t spanGroupEndIndex = len; - const uint32_t span = step2Items[i].mSpan; - for (++i; i < len; ++i) { - if (step2Items[i].mSpan != span) { - spanGroupEndIndex = i; - break; - } - } - + nsTArray itemPlan(mSizes.Length()); + itemPlan.SetLength(mSizes.Length()); + // Start / end iterator for items of the same span length: + auto spanGroupStart = step2Items.begin(); + auto spanGroupEnd = spanGroupStart; + const auto end = step2Items.end(); + for (; spanGroupStart != end; spanGroupStart = spanGroupEnd) { + while (spanGroupEnd != end && + !Step2ItemData::IsSpanLessThan(*spanGroupStart, *spanGroupEnd)) { + ++spanGroupEnd; + } + + const uint32_t span = spanGroupStart->mSpan; bool updatedBase = false; // Did we update any mBase in step 2.1 - 2.3? TrackSize::StateBits selector(TrackSize::eIntrinsicMinSizing); if (stateBitsPerSpan[span] & selector) { // Step 2.1 MinSize to intrinsic min-sizing. - for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) { - Step2ItemData& item = step2Items[i]; - if (!(item.mState & selector)) { - continue; - } - nscoord space = item.mMinSize; - if (space <= 0) { - continue; - } - tracks.ClearAndRetainStorage(); - space = CollectGrowable(space, mSizes, item.mLineRange, selector, - tracks); - if (space > 0) { - DistributeToTrackBases(space, plan, tracks, selector); - updatedBase = true; - } - } + updatedBase = + GrowSizeForSpanningItems( + spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector); } selector = contentBasedMinSelector; if (stateBitsPerSpan[span] & selector) { // Step 2.2 MinContentContribution to min-/max-content (and 'auto' when // sizing under a min-content constraint) min-sizing. - for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) { - Step2ItemData& item = step2Items[i]; - if (!(item.mState & selector)) { - continue; - } - nscoord space = item.mMinContentContribution; - if (space <= 0) { - continue; - } - tracks.ClearAndRetainStorage(); - space = CollectGrowable(space, mSizes, item.mLineRange, selector, - tracks); - if (space > 0) { - DistributeToTrackBases(space, plan, tracks, selector); - updatedBase = true; - } - } + updatedBase |= + GrowSizeForSpanningItems( + spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector); } selector = maxContentMinSelector; if (stateBitsPerSpan[span] & selector) { // Step 2.3 MaxContentContribution to max-content (and 'auto' when // sizing under a max-content constraint) min-sizing. - for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) { - Step2ItemData& item = step2Items[i]; - if (!(item.mState & selector)) { - continue; - } - nscoord space = item.mMaxContentContribution; - if (space <= 0) { - continue; - } - tracks.ClearAndRetainStorage(); - space = CollectGrowable(space, mSizes, item.mLineRange, selector, - tracks); - if (space > 0) { - DistributeToTrackBases(space, plan, tracks, selector); - updatedBase = true; - } - } + updatedBase |= + GrowSizeForSpanningItems( + spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector); } if (updatedBase) { @@ -4596,63 +4738,22 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize( } } } - if (stateBitsPerSpan[span] & TrackSize::eIntrinsicMaxSizing) { - plan = mSizes; - for (TrackSize& sz : plan) { - if (sz.mLimit == NS_UNCONSTRAINEDSIZE) { - // use mBase as the planned limit - } else { - sz.mBase = sz.mLimit; - } - } + selector = TrackSize::eIntrinsicMaxSizing; + if (stateBitsPerSpan[span] & selector) { + const bool willRunStep2_6 = + stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing; // Step 2.5 MinSize to intrinsic max-sizing. - for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) { - Step2ItemData& item = step2Items[i]; - if (!(item.mState & TrackSize::eIntrinsicMaxSizing)) { - continue; - } - nscoord space = item.mMinSize; - if (space <= 0) { - continue; - } - tracks.ClearAndRetainStorage(); - space = CollectGrowable(space, plan, item.mLineRange, - TrackSize::eIntrinsicMaxSizing, - tracks); - if (space > 0) { - DistributeToTrackLimits(space, plan, tracks, aFunctions, - aPercentageBasis); - } - } - for (size_t j = 0, len = mSizes.Length(); j < len; ++j) { - TrackSize& sz = plan[j]; - sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited); - if (sz.mLimit != NS_UNCONSTRAINEDSIZE) { - sz.mLimit = sz.mBase; // collect the results from 2.5 - } - } + GrowSizeForSpanningItems( + spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector, + fitContentClamper, willRunStep2_6); - if (stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing) { + if (willRunStep2_6) { // Step 2.6 MaxContentContribution to max-content max-sizing. - for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) { - Step2ItemData& item = step2Items[i]; - if (!(item.mState & TrackSize::eAutoOrMaxContentMaxSizing)) { - continue; - } - nscoord space = item.mMaxContentContribution; - if (space <= 0) { - continue; - } - tracks.ClearAndRetainStorage(); - space = CollectGrowable(space, plan, item.mLineRange, - TrackSize::eAutoOrMaxContentMaxSizing, - tracks); - if (space > 0) { - DistributeToTrackLimits(space, plan, tracks, aFunctions, - aPercentageBasis); - } - } + selector = TrackSize::eAutoOrMaxContentMaxSizing; + GrowSizeForSpanningItems( + spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector, + fitContentClamper); } } } @@ -4984,6 +5085,7 @@ nsGridContainerFrame::Tracks::AlignJustifyContent( default: MOZ_ASSERT_UNREACHABLE("unknown align-/justify-content value"); between = 0; // just to avoid a compiler warning + roundingError = 0; // just to avoid a compiler warning } between += mGridGap; for (TrackSize& sz : mSizes) { @@ -7113,6 +7215,9 @@ nsGridContainerFrame::TrackSize::Dump() const if (mState & eFrozen) { printf("frozen "); } + if (mState & eModified) { + printf("modified "); + } if (mState & eBreakBefore) { printf("break-before "); } -- cgit v1.2.3 From f1adcd1eeed03591f10ecc72c5e5b71856a18ca9 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 28 Sep 2019 23:25:06 -0400 Subject: Issue #1233 - Part 2: Update Reftests List of relevant patches applied: 1425599 part 15 - [css-grid] Test reference fixes + more tests. 1373678 Part 3: Add line number checks to test_grid_implicit.html. 1416350 - Part 3: Add test to verify line numbers of grids with leading implicit tracks. 1416350 - Part 4: Add a reftest of repeat:auto-fit grids with leading implicit tracks. 1417711 - [css-grid] An abs.pos. grid container child that only covers removed 'auto-fit' tracks should not span to the end padding edge. 1416350 - Part 5: Correct the expected results for grids that have leading implicit tracks. 1418727 part 3 - [css-grid] Reftest updates. --- layout/generic/nsGridContainerFrame.cpp | 10 +- layout/generic/test/mochitest.ini | 4 + .../test/test_grid_track_sizing_algo_001.html | 1641 ++++++++++++++++++++ .../test/test_grid_track_sizing_algo_002.html | 1641 ++++++++++++++++++++ .../grid-col-max-sizing-max-content-001-ref.html | 15 +- .../grid-col-max-sizing-max-content-002-ref.html | 15 +- .../css-grid/grid-flex-min-sizing-002-ref.html | 8 +- .../css-grid/grid-max-sizing-flex-004-ref.html | 4 +- .../grid-repeat-auto-fill-fit-006-ref.html | 64 +- .../grid-repeat-auto-fill-fit-007-ref.html | 22 +- .../grid-repeat-auto-fill-fit-008-ref.html | 33 +- .../css-grid/grid-repeat-auto-fill-fit-008.html | 34 +- .../grid-repeat-auto-fill-fit-012-ref.html | 144 ++ .../css-grid/grid-repeat-auto-fill-fit-012.html | 160 ++ .../grid-repeat-auto-fill-fit-013-ref.html | 116 ++ .../css-grid/grid-repeat-auto-fill-fit-013.html | 135 ++ .../grid-track-intrinsic-sizing-002-ref.html | 30 +- .../grid-track-intrinsic-sizing-003-ref.html | 48 +- layout/reftests/css-grid/reftest.list | 6 +- 19 files changed, 3988 insertions(+), 142 deletions(-) create mode 100644 layout/generic/test/test_grid_track_sizing_algo_001.html create mode 100644 layout/generic/test/test_grid_track_sizing_algo_002.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-012-ref.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-012.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-013-ref.html create mode 100644 layout/reftests/css-grid/grid-repeat-auto-fill-fit-013.html (limited to 'layout') diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 59f58f268..054f01297 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -725,9 +725,6 @@ struct nsGridContainerFrame::LineRange mEnd > mStart, "invalid line range"); mEnd -= aNumRemovedTracks[mEnd]; } - if (mStart == mEnd) { - mEnd = nsGridContainerFrame::kAutoLine; - } } /** * Return the contribution of this line range for step 2 in @@ -5179,10 +5176,15 @@ nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos( : GridLineSide::eBeforeGridGap; nscoord endPos = aTracks.GridLineEdge(mEnd, side); *aLength = std::max(aGridOrigin + endPos, 0); - } else { + } else if (MOZ_LIKELY(mStart != mEnd)) { nscoord pos; ToPositionAndLength(aTracks.mSizes, &pos, aLength); *aPos = aGridOrigin + pos; + } else { + // The grid area only covers removed 'auto-fit' tracks. + nscoord pos = aTracks.GridLineEdge(mStart, GridLineSide::eBeforeGridGap); + *aPos = aGridOrigin + pos; + *aLength = nscoord(0); } } } diff --git a/layout/generic/test/mochitest.ini b/layout/generic/test/mochitest.ini index 934ffc8a4..33dacddab 100644 --- a/layout/generic/test/mochitest.ini +++ b/layout/generic/test/mochitest.ini @@ -138,3 +138,7 @@ support-files = file_taintedfilters_feDisplacementMap-tainted-1.svg file_tainted support-files = file_scroll_position_restore.html [test_scroll_animation_restore.html] [test_scroll_position_iframe.html] +[test_grid_track_sizing_algo_001.html] +skip-if = debug == true # the test is slow +[test_grid_track_sizing_algo_002.html] +skip-if = debug == true # the test is slow diff --git a/layout/generic/test/test_grid_track_sizing_algo_001.html b/layout/generic/test/test_grid_track_sizing_algo_001.html new file mode 100644 index 000000000..68956c2df --- /dev/null +++ b/layout/generic/test/test_grid_track_sizing_algo_001.html @@ -0,0 +1,1641 @@ + + + + + CSS Grid Test: intrinsic track sizing with spanning items + + + + + + + + + + + + + + + diff --git a/layout/generic/test/test_grid_track_sizing_algo_002.html b/layout/generic/test/test_grid_track_sizing_algo_002.html new file mode 100644 index 000000000..40f50e20f --- /dev/null +++ b/layout/generic/test/test_grid_track_sizing_algo_002.html @@ -0,0 +1,1641 @@ + + + + + CSS Grid Test: intrinsic track sizing with spanning items + + + + + + + + + + + + + + + diff --git a/layout/reftests/css-grid/grid-col-max-sizing-max-content-001-ref.html b/layout/reftests/css-grid/grid-col-max-sizing-max-content-001-ref.html index eda06249b..da30a8b89 100644 --- a/layout/reftests/css-grid/grid-col-max-sizing-max-content-001-ref.html +++ b/layout/reftests/css-grid/grid-col-max-sizing-max-content-001-ref.html @@ -17,9 +17,9 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0; clear:left; } -.c1 { min-width:40px; margin-bottom: 2px; margin-right: 47px; } +.c1 { width:40px; margin-bottom: 2px; margin-right: 47px; } .r1 { min-width:70px; margin-left: 38px; margin-top: 2px; } -.c3 { min-width:0; margin: 2px 18px 1px 85px; } +.c3 { width:10px; margin: 2px 18px 1px 71px; } span { display: block; @@ -52,21 +52,22 @@ x { display:inline-block; width:10px; height:18px; }     +
-  +     
-  +       
-  +     
@@ -74,13 +75,13 @@ x { display:inline-block; width:10px; height:18px; }
    -  + 
    -  + 
diff --git a/layout/reftests/css-grid/grid-col-max-sizing-max-content-002-ref.html b/layout/reftests/css-grid/grid-col-max-sizing-max-content-002-ref.html index 23ca12e7b..eeb4e407f 100644 --- a/layout/reftests/css-grid/grid-col-max-sizing-max-content-002-ref.html +++ b/layout/reftests/css-grid/grid-col-max-sizing-max-content-002-ref.html @@ -21,9 +21,9 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0; clear:left; } -.c1 { min-width:40px; margin-bottom: 2px; margin-right: 47px; } +.c1 { width:40px; margin-bottom: 2px; margin-right: 47px; } .r1 { min-width:70px; margin-left: 38px; margin-top: 2px; } -.c3 { min-width:0; margin: 2px 18px 1px 85px; } +.c3 { width:10px; margin: 2px 18px 1px 71px; } span { display: block; @@ -56,21 +56,22 @@ x { display:inline-block; width:10px; height:18px; }     +
-  +     
-  +       
-  +     
@@ -78,13 +79,13 @@ x { display:inline-block; width:10px; height:18px; }
    -  + 
    -  + 
diff --git a/layout/reftests/css-grid/grid-flex-min-sizing-002-ref.html b/layout/reftests/css-grid/grid-flex-min-sizing-002-ref.html index d9af7e43c..d811447ff 100644 --- a/layout/reftests/css-grid/grid-flex-min-sizing-002-ref.html +++ b/layout/reftests/css-grid/grid-flex-min-sizing-002-ref.html @@ -127,10 +127,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px } .gF { - grid-template-columns: 22px - 1px - 1px - auto; + grid-template-columns: 2px + 20px + 2px + 0; } diff --git a/layout/reftests/css-grid/grid-max-sizing-flex-004-ref.html b/layout/reftests/css-grid/grid-max-sizing-flex-004-ref.html index 6446c0ee6..b0ac02bf5 100644 --- a/layout/reftests/css-grid/grid-max-sizing-flex-004-ref.html +++ b/layout/reftests/css-grid/grid-max-sizing-flex-004-ref.html @@ -51,8 +51,8 @@ x { display:inline-block; height:10px; width:18px; }
--> -
-
+
+
+ + + Reference: repeat(auto-fit) with removed tracks + + + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-012.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-012.html new file mode 100644 index 000000000..7ed0843af --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-012.html @@ -0,0 +1,160 @@ + + + + + CSS Grid Test: repeat(auto-fit) with removed tracks + + + + + + + +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013-ref.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013-ref.html new file mode 100644 index 000000000..9b8267f88 --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013-ref.html @@ -0,0 +1,116 @@ + + + + +CSS Grid Test Reference: test auto placement in repeat auto-fit grids with leading implicit tracks + + + + +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + + diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013.html new file mode 100644 index 000000000..5a9c05d73 --- /dev/null +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-013.html @@ -0,0 +1,135 @@ + + + + +CSS Grid Test: test placement in repeat auto-fit grids with leading implicit tracks + + + + + + + +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + + diff --git a/layout/reftests/css-grid/grid-track-intrinsic-sizing-002-ref.html b/layout/reftests/css-grid/grid-track-intrinsic-sizing-002-ref.html index 7fb00f1da..23dc42b69 100644 --- a/layout/reftests/css-grid/grid-track-intrinsic-sizing-002-ref.html +++ b/layout/reftests/css-grid/grid-track-intrinsic-sizing-002-ref.html @@ -27,34 +27,34 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px background: grey; } .g1 .d1 { - width: 52px; + width: 0px; } .g2 .d1 { - width: 56px; + width: 0px; } .g2f .d1 { - width: 69px; + width: 0px; } .g3 .d1 { - width: 56px; + width: 0px; } .g4 .d1 { - width: 96px; + width: 80px; } .g4f .d1 { - width: 69px; + width: 0px; } .g5 .d1 { - width: 96px; + width: 80px; } .g6 .d1 { - width: 69px; + width: 0px; } .g6f .d1 { - width: 69px; + width: 0px; } .g7 .d1 { - width: 69px; + width: 0px; } .g8 .t { width: 196px; @@ -63,19 +63,19 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px width: 200px; } .g9 .d1 { - width: 69px; + width: 0px; } .gA .d1 { - width: 93px; + width: 80px; } .gB .d1 { - width: 93px; + width: 80px; } .gC .d1 { - width: 93px; + width: 80px; } .gD .d1 { - width: 93px; + width: 80px; } .t { grid-column: span 1; border:2px solid; } diff --git a/layout/reftests/css-grid/grid-track-intrinsic-sizing-003-ref.html b/layout/reftests/css-grid/grid-track-intrinsic-sizing-003-ref.html index bc52f4ca0..01739578c 100644 --- a/layout/reftests/css-grid/grid-track-intrinsic-sizing-003-ref.html +++ b/layout/reftests/css-grid/grid-track-intrinsic-sizing-003-ref.html @@ -27,34 +27,34 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px background: grey; } .g1 .d1 { - width: 52px; + width: 0px; } .g2 .d1 { - width: 56px; + width: 0px; } .g2f .d1 { width: 69px; } .g3 .d1 { - width: 56px; + width: 0px; } .g4 .d1 { - width: 96px; + width: 80px; } .g4f .d1 { width: 104px; } .g5 .d1 { - width: 96px; + width: 80px; } .g6 .d1 { - width: 69px; + width: 0px; } .g6f .d1 { width: 89px; } .g7 .d1 { - width: 69px; + width: 0px; } .g8 .t { width: 196px; @@ -63,19 +63,19 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px width: 200px; } .g9 .d1 { - width: 69px; + width: 0px; } .gA .d1 { - width: 93px; + width: 80px; } .gB .d1 { - width: 93px; + width: 80px; } .gC .d1 { - width: 93px; + width: 80px; } .gD .d1 { - width: 93px; + width: 80px; } .d2 { position: absolute; @@ -84,10 +84,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px background: blue; } .g1 .d2 { - width: 448px; + width: 500px; } .g2 .d2 { - width: 444px; + width: 500px; } .g2f .d2 { right: auto; @@ -95,10 +95,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px width: 35px; } .g3 .d2 { - width: 444px; + width: 500px; } .g4 .d2 { - width: 404px; + width: 420px; } .g4f .d2 { right: auto; @@ -106,10 +106,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px width: 35px; } .g5 .d2 { - width: 404px; + width: 420px; } .g6 .d2 { - width: 431px; + width: 500px; } .g6f .d2 { right: auto; @@ -117,25 +117,25 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px width: 35px; } .g7 .d2 { - width: 431px; + width: 500px; } .g8 .d2 { width: 300px; } .g9 .d2 { - width: 431px; + width: 500px; } .gA .d2 { - width: 407px; + width: 420px; } .gB .d2 { - width: 407px; + width: 420px; } .gC .d2 { - width: 407px; + width: 420px; } .gD .d2 { - width: 407px; + width: 420px; } .t { grid-column: span 1; border:2px solid; } diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list index 3087ca49b..7c5e6be51 100644 --- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -112,9 +112,9 @@ skip-if(Android) == grid-auto-min-sizing-percent-001.html grid-auto-min-sizing-p == grid-item-auto-min-size-clamp-001.html grid-item-auto-min-size-clamp-001-ref.html == grid-item-auto-min-size-clamp-002.html grid-item-auto-min-size-clamp-002-ref.html == grid-item-auto-min-size-clamp-003.html grid-item-auto-min-size-clamp-003-ref.html -== grid-item-auto-min-size-clamp-004.html grid-item-auto-min-size-clamp-004-ref.html +# == grid-item-auto-min-size-clamp-004.html grid-item-auto-min-size-clamp-004-ref.html # bug 1421976 == grid-item-auto-min-size-clamp-005.html grid-item-auto-min-size-clamp-005-ref.html -== grid-item-auto-min-size-clamp-006.html grid-item-auto-min-size-clamp-006-ref.html +# == grid-item-auto-min-size-clamp-006.html grid-item-auto-min-size-clamp-006-ref.html # bug 1421976 == grid-item-auto-min-size-clamp-007.html grid-item-auto-min-size-clamp-007-ref.html == grid-item-overflow-stretch-001.html grid-item-overflow-stretch-001-ref.html == grid-item-overflow-stretch-002.html grid-item-overflow-stretch-002-ref.html @@ -184,6 +184,8 @@ skip-if(Android&&isDebugBuild) == grid-row-gap-004.html grid-row-gap-004-ref.htm == grid-repeat-auto-fill-fit-009.html grid-repeat-auto-fill-fit-009-ref.html == grid-repeat-auto-fill-fit-010.html grid-repeat-auto-fill-fit-010-ref.html == grid-repeat-auto-fill-fit-011.html grid-repeat-auto-fill-fit-010-ref.html +== grid-repeat-auto-fill-fit-012.html grid-repeat-auto-fill-fit-012-ref.html +== grid-repeat-auto-fill-fit-013.html grid-repeat-auto-fill-fit-013-ref.html == grid-item-blockifying-001.html grid-item-blockifying-001-ref.html == grid-fragmentation-001.html grid-fragmentation-001-ref.html == grid-fragmentation-002.html grid-fragmentation-002-ref.html -- cgit v1.2.3 From 8ff295747e7f5e205313e4405d5a63ce23fca993 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 28 Sep 2019 23:36:05 -0400 Subject: Issue #1230 - Part 1: Fix Back-computing percentages for intrinsic sizing in Layout CSS-Grid List of relevant patches applied: 1398537 part 2 - [css-multicol] Implement percentages for 'column-gap' (Gecko part). 1434478 part 1 - [css-grid] Stop back-computing percentage grid gaps when the percentage basis is indefinite. Treat them as zero sized instead. 1434478 part 2 - Stop back-computing percentage padding/margin when the percentage basis is indefinite. Treat them as zero sized instead. 1434478 part 3 - Remove IntrinsicISizeOffsetData::hPctPadding/hPctMargin members since they are now unused. 1434478 part 4 - Factor out constants like NS_UNCONSTRAINEDSIZE so they can be used in headers without needing nsIFrame.h (idempotent patch). 1434478 part 5 - Create nsLayoutUtils::ResolveToLength for resolving CSS (idempotent patch). 1434478 part 6 - Propagate a percentage basis to nsIFrame::IntrinsicISizeOffsets for resolving padding/margin. This is needed only for CSS Grid since in other cases we're only using IntrinsicISizeOffsets in the inline-axis and the percentage basis is always indefinite for *intrinsic sizing*. When calculating the intrinsic size of grid items in the grid container's block axis however, we do have a definite size for the grid area in the inline-axis and it should be used per: https://drafts.csswg.org/css-grid/#algo-overview "2. Next, the track sizing algorithm resolves the sizes of the grid rows, using the grid column sizes calculated in the previous step." (Percentage padding/margin for grid items is always resolved against the grid area's inline-size nowadays.) --- layout/base/LayoutConstants.h | 31 ++++++ layout/base/moz.build | 4 + layout/base/nsLayoutUtils.cpp | 76 +++++--------- layout/base/nsLayoutUtils.h | 95 ++++++++++++----- layout/generic/nsColumnSetFrame.cpp | 19 ++-- layout/generic/nsFrame.cpp | 93 ++++++----------- layout/generic/nsFrame.h | 3 +- layout/generic/nsGridContainerFrame.cpp | 180 +++++++------------------------- layout/generic/nsIFrame.h | 31 ++---- layout/style/nsCSSPropList.h | 2 +- layout/style/nsStyleStruct.h | 2 +- layout/style/test/property_database.js | 4 +- layout/tables/nsTableCellFrame.cpp | 6 +- layout/tables/nsTableCellFrame.h | 3 +- layout/tables/nsTableFrame.cpp | 7 +- layout/tables/nsTableFrame.h | 3 +- 16 files changed, 240 insertions(+), 319 deletions(-) create mode 100644 layout/base/LayoutConstants.h (limited to 'layout') diff --git a/layout/base/LayoutConstants.h b/layout/base/LayoutConstants.h new file mode 100644 index 000000000..cd6e1c3f5 --- /dev/null +++ b/layout/base/LayoutConstants.h @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* constants used throughout the Layout module */ + +#ifndef LayoutConstants_h___ +#define LayoutConstants_h___ + +#include "nsSize.h" // for NS_MAXSIZE + +/** + * Constant used to indicate an unconstrained size. + */ +#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE + +// NOTE: There are assumptions all over that these have the same value, +// namely NS_UNCONSTRAINEDSIZE. +#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE +#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE +#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE + +// +1 is to avoid clamped huge margin values being processed as auto margins +#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1) + +#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN + + +#endif // LayoutConstants_h___ diff --git a/layout/base/moz.build b/layout/base/moz.build index 4308a6e4d..afc683665 100644 --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -13,6 +13,9 @@ with Files('Display*'): with Files('FrameLayerBuilder.*'): BUG_COMPONENT = ('Core', 'Layout: View Rendering') +with Files('LayoutConstants.*'): + BUG_COMPONENT = ('Core', 'Layout: View Rendering') + with Files('LayerState.*'): BUG_COMPONENT = ('Core', 'Layout: View Rendering') @@ -63,6 +66,7 @@ EXPORTS += [ 'FrameLayerBuilder.h', 'FrameProperties.h', 'LayerState.h', + 'LayoutConstants.h', 'LayoutLogging.h', 'nsArenaMemoryStats.h', 'nsBidi.h', diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 06690b208..21d20c69f 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4671,8 +4671,6 @@ GetDefiniteSize(const nsStyleCoord& aStyle, nscoord pb = aIsInlineAxis ? aPercentageBasis.value().ISize(wm) : aPercentageBasis.value().BSize(wm); if (pb == NS_UNCONSTRAINEDSIZE) { - // XXXmats given that we're calculating an intrinsic size here, - // maybe we should back-compute the calc-size using AddPercents? return false; } *aResult = std::max(0, calc->mLength + @@ -4916,12 +4914,9 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, nscoord result = aContentSize; nscoord min = aContentMinSize; nscoord coordOutsideSize = 0; - float pctOutsideSize = 0; - float pctTotal = 0.0f; if (!(aFlags & nsLayoutUtils::IGNORE_PADDING)) { coordOutsideSize += aOffsets.hPadding; - pctOutsideSize += aOffsets.hPctPadding; } coordOutsideSize += aOffsets.hBorder; @@ -4929,21 +4924,15 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, if (aBoxSizing == StyleBoxSizing::Border) { min += coordOutsideSize; result = NSCoordSaturatingAdd(result, coordOutsideSize); - pctTotal += pctOutsideSize; coordOutsideSize = 0; - pctOutsideSize = 0.0f; } coordOutsideSize += aOffsets.hMargin; - pctOutsideSize += aOffsets.hPctMargin; min += coordOutsideSize; result = NSCoordSaturatingAdd(result, coordOutsideSize); - pctTotal += pctOutsideSize; - const bool shouldAddPercent = aType == nsLayoutUtils::PREF_ISIZE || - (aFlags & nsLayoutUtils::ADD_PERCENTS); nscoord size; if (aType == nsLayoutUtils::MIN_ISIZE && (((aStyleSize.HasPercent() || aStyleMaxSize.HasPercent()) && @@ -4961,18 +4950,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame, PROP_WIDTH, size)) { result = size + coordOutsideSize; - if (shouldAddPercent) { - result = nsLayoutUtils::AddPercents(result, pctOutsideSize); - } - } else { - // NOTE: We could really do a lot better for percents and for some - // cases of calc() containing percent (certainly including any where - // the coefficient on the percent is positive and there are no max() - // expressions). However, doing better for percents wouldn't be - // backwards compatible. - if (shouldAddPercent) { - result = nsLayoutUtils::AddPercents(result, pctTotal); - } } nscoord maxSize = aFixedMaxSize ? *aFixedMaxSize : 0; @@ -4980,9 +4957,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, GetIntrinsicCoord(aStyleMaxSize, aRenderingContext, aFrame, PROP_MAX_WIDTH, maxSize)) { maxSize += coordOutsideSize; - if (shouldAddPercent) { - maxSize = nsLayoutUtils::AddPercents(maxSize, pctOutsideSize); - } if (result > maxSize) { result = maxSize; } @@ -4993,17 +4967,11 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, GetIntrinsicCoord(aStyleMinSize, aRenderingContext, aFrame, PROP_MIN_WIDTH, minSize)) { minSize += coordOutsideSize; - if (shouldAddPercent) { - minSize = nsLayoutUtils::AddPercents(minSize, pctOutsideSize); - } if (result < minSize) { result = minSize; } } - if (shouldAddPercent) { - min = nsLayoutUtils::AddPercents(min, pctTotal); - } if (result < min) { result = min; } @@ -5020,9 +4988,6 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, : devSize.width); // GetMinimumWidgetSize() returns a border-box width. themeSize += aOffsets.hMargin; - if (shouldAddPercent) { - themeSize = nsLayoutUtils::AddPercents(themeSize, aOffsets.hPctMargin); - } if (themeSize > result || !canOverride) { result = themeSize; } @@ -5267,9 +5232,19 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, min = aFrame->GetMinISize(aRenderingContext); } + nscoord pmPercentageBasis = NS_UNCONSTRAINEDSIZE; + if (aPercentageBasis.isSome()) { + // The padding/margin percentage basis is the inline-size in the parent's + // writing-mode. + auto childWM = aFrame->GetWritingMode(); + pmPercentageBasis = + aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ? + aPercentageBasis->BSize(childWM) : + aPercentageBasis->ISize(childWM); + } nsIFrame::IntrinsicISizeOffsetData offsets = - MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets() - : aFrame->IntrinsicBSizeOffsets(); + MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis) + : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis); nscoord contentBoxSize = result; result = AddIntrinsicSizeOffset(aRenderingContext, aFrame, offsets, aType, boxSizing, result, min, styleISize, @@ -5310,11 +5285,12 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext* aRenderingContext, } /* static */ nscoord -nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, +nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, nsRenderingContext* aRC, - nsIFrame* aFrame, - IntrinsicISizeType aType, - uint32_t aFlags) + nsIFrame* aFrame, + IntrinsicISizeType aType, + const LogicalSize& aPercentageBasis, + uint32_t aFlags) { MOZ_ASSERT(aFrame); MOZ_ASSERT(aFrame->IsFlexOrGridItem(), @@ -5328,9 +5304,7 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, aWM.IsVertical() ? "vertical" : "horizontal"); #endif - // Note: this method is only meant for grid/flex items which always - // include percentages in their intrinsic size. - aFlags |= nsLayoutUtils::ADD_PERCENTS; + // Note: this method is only meant for grid/flex items. const nsStylePosition* const stylePos = aFrame->StylePosition(); const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth : &stylePos->mMinHeight; @@ -5375,11 +5349,17 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, // wrapping inside of it should not apply font size inflation. AutoMaybeDisableFontInflation an(aFrame); - PhysicalAxis ourInlineAxis = - aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline); + // The padding/margin percentage basis is the inline-size in the parent's + // writing-mode. + auto childWM = aFrame->GetWritingMode(); + nscoord pmPercentageBasis = + aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ? + aPercentageBasis.BSize(childWM) : + aPercentageBasis.ISize(childWM); + PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline); nsIFrame::IntrinsicISizeOffsetData offsets = - ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets() - : aFrame->IntrinsicBSizeOffsets(); + ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis) + : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis); nscoord result = 0; nscoord min = 0; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 0a82dbf6a..bba1f3265 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -6,6 +6,7 @@ #ifndef nsLayoutUtils_h__ #define nsLayoutUtils_h__ +#include "LayoutConstants.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Maybe.h" @@ -154,6 +155,7 @@ public: typedef mozilla::ScreenMargin ScreenMargin; typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; typedef mozilla::StyleGeometryBox StyleGeometryBox; + typedef mozilla::LogicalSize LogicalSize; /** * Finds previously assigned ViewID for the given content element, if any. @@ -1381,7 +1383,8 @@ public: * variations if that's what matches aAxis) and its padding, border and margin * in the corresponding dimension. * @param aPercentageBasis an optional percentage basis (in aFrame's WM). - * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes. + * If the basis is indefinite in a given axis, pass a size with + * NS_UNCONSTRAINEDSIZE in that component. * If you pass Nothing() a percentage basis will be calculated from aFrame's * ancestors' computed size in the relevant axis, if needed. * @param aMarginBoxMinSizeClamp make the result fit within this margin-box @@ -1395,14 +1398,13 @@ public: IGNORE_PADDING = 0x01, BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_WIDTH_UNKNOWN if so MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height - ADD_PERCENTS = 0x08, // apply AddPercents also for MIN_ISIZE }; static nscoord IntrinsicForAxis(mozilla::PhysicalAxis aAxis, nsRenderingContext* aRenderingContext, nsIFrame* aFrame, IntrinsicISizeType aType, - const mozilla::Maybe& aPercentageBasis = mozilla::Nothing(), + const mozilla::Maybe& aPercentageBasis = mozilla::Nothing(), uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE); /** @@ -1427,31 +1429,18 @@ public: * calculates the result as if the 'min-' computed value is zero. * Otherwise, return NS_UNCONSTRAINEDSIZE. * + * @param aPercentageBasis the percentage basis (in aFrame's WM). + * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes. * @note this behavior is specific to Grid/Flexbox (currently) so aFrame * should be a grid/flex item. */ - static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis, - nsRenderingContext* aRC, - nsIFrame* aFrame, - IntrinsicISizeType aType, - uint32_t aFlags = 0); - - /** - * This function increases an initial intrinsic size, 'aCurrent', according - * to the given 'aPercent', such that the size-increase makes up exactly - * 'aPercent' percent of the returned value. If 'aPercent' or 'aCurrent' are - * less than or equal to zero the original 'aCurrent' value is returned. - * If 'aPercent' is greater than or equal to 1.0 the value nscoord_MAX is - * returned. - */ - static nscoord AddPercents(nscoord aCurrent, float aPercent) - { - if (aPercent > 0.0f && aCurrent > 0) { - return MOZ_UNLIKELY(aPercent >= 1.0f) ? nscoord_MAX - : NSToCoordRound(float(aCurrent) / (1.0f - aPercent)); - } - return aCurrent; - } + static nscoord + MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis, + nsRenderingContext* aRC, + nsIFrame* aFrame, + IntrinsicISizeType aType, + const LogicalSize& aPercentageBasis, + uint32_t aFlags = 0); /* * Convert nsStyleCoord to nscoord when percentages depend on the @@ -2876,6 +2865,62 @@ public: static nsRect ComputeGeometryBox(nsIFrame* aFrame, StyleGeometryBox aGeometryBox); + /** + * Resolve a CSS value to a definite size. + */ + template + static nscoord ResolveToLength(const nsStyleCoord& aCoord, + nscoord aPercentageBasis) + { + NS_WARNING_ASSERTION(aPercentageBasis >= nscoord(0), "nscoord overflow?"); + + switch (aCoord.GetUnit()) { + case eStyleUnit_Coord: + MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetCoordValue() >= 0, + "This value should have been rejected by the style system"); + return aCoord.GetCoordValue(); + case eStyleUnit_Percent: + if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { + return nscoord(0); + } + MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetPercentValue() >= 0, + "This value should have been rejected by the style system"); + return NSToCoordFloorClamped(aPercentageBasis * + aCoord.GetPercentValue()); + case eStyleUnit_Calc: { + nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); + nscoord result; + if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { + result = calc->mLength; + } else { + result = calc->mLength + + NSToCoordFloorClamped(aPercentageBasis * calc->mPercent); + } + if (clampNegativeResultToZero && result < 0) { + return nscoord(0); + } + return result; + } + default: + MOZ_ASSERT_UNREACHABLE("Unexpected unit!"); + return nscoord(0); + } + } + + /** + * Resolve a column-gap/row-gap to a definite size. + * @note This method resolves 'normal' to zero. + * Callers who want different behavior should handle 'normal' on their own. + */ + static nscoord ResolveGapToLength(const nsStyleCoord& aGap, + nscoord aPercentageBasis) + { + if (aGap.GetUnit() == eStyleUnit_Normal) { + return nscoord(0); + } + return ResolveToLength(aGap, aPercentageBasis); + } + private: static uint32_t sFontSizeInflationEmPerLine; static uint32_t sFontSizeInflationMinTwips; diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp index ad36ba1a8..6ea15d4d2 100644 --- a/layout/generic/nsColumnSetFrame.cpp +++ b/layout/generic/nsColumnSetFrame.cpp @@ -183,18 +183,15 @@ nsColumnSetFrame::GetAvailableContentBSize(const ReflowInput& aReflowInput) static nscoord GetColumnGap(nsColumnSetFrame* aFrame, - const nsStyleColumn* aColStyle) + const nsStyleColumn* aColStyle, + nscoord aPercentageBasis) { - if (eStyleUnit_Normal == aColStyle->mColumnGap.GetUnit()) + const auto& columnGap = aColStyle->mColumnGap; + if (columnGap.GetUnit() == eStyleUnit_Normal) { return aFrame->StyleFont()->mFont.size; - if (eStyleUnit_Coord == aColStyle->mColumnGap.GetUnit()) { - nscoord colGap = aColStyle->mColumnGap.GetCoordValue(); - NS_ASSERTION(colGap >= 0, "negative column gap"); - return colGap; } - NS_NOTREACHED("Unknown gap type"); - return 0; + return nsLayoutUtils::ResolveGapToLength(columnGap, aPercentageBasis); } nsColumnSetFrame::ReflowConfig @@ -227,7 +224,7 @@ nsColumnSetFrame::ChooseColumnStrategy(const ReflowInput& aReflowInput, colBSize = std::min(colBSize, aReflowInput.ComputedMaxBSize()); } - nscoord colGap = GetColumnGap(this, colStyle); + nscoord colGap = GetColumnGap(this, colStyle, aReflowInput.ComputedISize()); int32_t numColumns = colStyle->mColumnCount; // If column-fill is set to 'balance', then we want to balance the columns. @@ -403,7 +400,7 @@ nsColumnSetFrame::GetMinISize(nsRenderingContext *aRenderingContext) // include n-1 column gaps. colISize = iSize; iSize *= colStyle->mColumnCount; - nscoord colGap = GetColumnGap(this, colStyle); + nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE); iSize += colGap * (colStyle->mColumnCount - 1); // The multiplication above can make 'width' negative (integer overflow), // so use std::max to protect against that. @@ -424,7 +421,7 @@ nsColumnSetFrame::GetPrefISize(nsRenderingContext *aRenderingContext) nscoord result = 0; DISPLAY_PREF_WIDTH(this, result); const nsStyleColumn* colStyle = StyleColumn(); - nscoord colGap = GetColumnGap(this, colStyle); + nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE); nscoord colISize; if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index bd96f213b..a531dea07 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4515,68 +4515,44 @@ nsIFrame::InlinePrefISizeData::ForceBreak() mSkipWhitespace = true; } -static void -AddCoord(const nsStyleCoord& aStyle, - nsIFrame* aFrame, - nscoord* aCoord, float* aPercent, - bool aClampNegativeToZero) -{ - switch (aStyle.GetUnit()) { - case eStyleUnit_Coord: { - NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0, - "unexpected negative value"); - *aCoord += aStyle.GetCoordValue(); - return; - } - case eStyleUnit_Percent: { - NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f, - "unexpected negative value"); - *aPercent += aStyle.GetPercentValue(); - return; - } - case eStyleUnit_Calc: { - const nsStyleCoord::Calc *calc = aStyle.GetCalcValue(); - if (aClampNegativeToZero) { - // This is far from ideal when one is negative and one is positive. - *aCoord += std::max(calc->mLength, 0); - *aPercent += std::max(calc->mPercent, 0.0f); - } else { - *aCoord += calc->mLength; - *aPercent += calc->mPercent; - } - return; - } - default: { - return; - } +static nscoord +ResolveMargin(const nsStyleCoord& aStyle, nscoord aPercentageBasis) +{ + if (aStyle.GetUnit() == eStyleUnit_Auto) { + return nscoord(0); } + return nsLayoutUtils::ResolveToLength(aStyle, aPercentageBasis); +} + +static nscoord +ResolvePadding(const nsStyleCoord& aStyle, nscoord aPercentageBasis) +{ + return nsLayoutUtils::ResolveToLength(aStyle, aPercentageBasis); } static nsIFrame::IntrinsicISizeOffsetData -IntrinsicSizeOffsets(nsIFrame* aFrame, bool aForISize) +IntrinsicSizeOffsets(nsIFrame* aFrame, nscoord aPercentageBasis, bool aForISize) { nsIFrame::IntrinsicISizeOffsetData result; WritingMode wm = aFrame->GetWritingMode(); - const nsStyleMargin* styleMargin = aFrame->StyleMargin(); + const auto& margin = aFrame->StyleMargin()->mMargin; bool verticalAxis = aForISize == wm.IsVertical(); - AddCoord(verticalAxis ? styleMargin->mMargin.GetTop() - : styleMargin->mMargin.GetLeft(), - aFrame, &result.hMargin, &result.hPctMargin, - false); - AddCoord(verticalAxis ? styleMargin->mMargin.GetBottom() - : styleMargin->mMargin.GetRight(), - aFrame, &result.hMargin, &result.hPctMargin, - false); - - const nsStylePadding* stylePadding = aFrame->StylePadding(); - AddCoord(verticalAxis ? stylePadding->mPadding.GetTop() - : stylePadding->mPadding.GetLeft(), - aFrame, &result.hPadding, &result.hPctPadding, - true); - AddCoord(verticalAxis ? stylePadding->mPadding.GetBottom() - : stylePadding->mPadding.GetRight(), - aFrame, &result.hPadding, &result.hPctPadding, - true); + if (verticalAxis) { + result.hMargin += ResolveMargin(margin.GetTop(), aPercentageBasis); + result.hMargin += ResolveMargin(margin.GetBottom(), aPercentageBasis); + } else { + result.hMargin += ResolveMargin(margin.GetLeft(), aPercentageBasis); + result.hMargin += ResolveMargin(margin.GetRight(), aPercentageBasis); + } + + const auto& padding = aFrame->StylePadding()->mPadding; + if (verticalAxis) { + result.hPadding += ResolvePadding(padding.GetTop(), aPercentageBasis); + result.hPadding += ResolvePadding(padding.GetBottom(), aPercentageBasis); + } else { + result.hPadding += ResolvePadding(padding.GetLeft(), aPercentageBasis); + result.hPadding += ResolvePadding(padding.GetRight(), aPercentageBasis); + } const nsStyleBorder* styleBorder = aFrame->StyleBorder(); if (verticalAxis) { @@ -4606,22 +4582,21 @@ IntrinsicSizeOffsets(nsIFrame* aFrame, bool aForISize) result.hPadding = presContext->DevPixelsToAppUnits(verticalAxis ? padding.TopBottom() : padding.LeftRight()); - result.hPctPadding = 0; } } return result; } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsFrame::IntrinsicISizeOffsets() +nsFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) { - return IntrinsicSizeOffsets(this, true); + return IntrinsicSizeOffsets(this, aPercentageBasis, true); } nsIFrame::IntrinsicISizeOffsetData -nsIFrame::IntrinsicBSizeOffsets() +nsIFrame::IntrinsicBSizeOffsets(nscoord aPercentageBasis) { - return IntrinsicSizeOffsets(this, false); + return IntrinsicSizeOffsets(this, aPercentageBasis, false); } /* virtual */ IntrinsicSize diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index af1c95ef2..439e39856 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -261,7 +261,8 @@ public: InlineMinISizeData *aData) override; virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext, InlinePrefISizeData *aData) override; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData + IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; virtual mozilla::IntrinsicSize GetIntrinsicSize() override; virtual nsSize GetIntrinsicRatio() override; diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 054f01297..959061e33 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -8,8 +8,8 @@ #include "nsGridContainerFrame.h" -#include // for std::stable_sort #include +#include // for div() #include "mozilla/CSSAlignUtils.h" #include "mozilla/dom/GridBinding.h" #include "mozilla/Function.h" @@ -127,43 +127,6 @@ ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis) nsRuleNode::ComputeCoordPercentCalc(aCoord, aPercentBasis)); } -static bool -GetPercentSizeParts(const nsStyleCoord& aCoord, nscoord* aLength, float* aPercent) -{ - switch (aCoord.GetUnit()) { - case eStyleUnit_Percent: - *aLength = 0; - *aPercent = aCoord.GetPercentValue(); - return true; - case eStyleUnit_Calc: { - nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); - *aLength = calc->mLength; - *aPercent = calc->mPercent; - return true; - } - default: - return false; - } -} - -static void -ResolvePercentSizeParts(const nsStyleCoord& aCoord, nscoord aPercentBasis, - nscoord* aLength, float* aPercent) -{ - MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit()); - if (aPercentBasis != NS_UNCONSTRAINEDSIZE) { - *aLength = std::max(nscoord(0), - nsRuleNode::ComputeCoordPercentCalc(aCoord, - aPercentBasis)); - *aPercent = 0.0f; - return; - } - if (!GetPercentSizeParts(aCoord, aLength, aPercent)) { - *aLength = aCoord.ToLength(); - *aPercent = 0.0f; - } -} - // Synthesize a baseline from a border box. For an alphabetical baseline // this is the end edge of the border box. For a central baseline it's // the center of the border box. @@ -1172,7 +1135,7 @@ struct nsGridContainerFrame::TrackSizingFunctions return 1; } nscoord repeatTrackSize = 0; - // Note that the repeat() track size is included in |sum| in this loop. + // Note that one repeat() track size is included in |sum| in this loop. nscoord sum = 0; const nscoord percentBasis = aSize; for (uint32_t i = 0; i < numTracks; ++i) { @@ -1189,54 +1152,31 @@ struct nsGridContainerFrame::TrackSizingFunctions } nscoord trackSize = ::ResolveToDefiniteSize(*coord, percentBasis); if (i == mRepeatAutoStart) { - if (percentBasis != NS_UNCONSTRAINEDSIZE) { - // Use a minimum 1px for the repeat() track-size. - if (trackSize < AppUnitsPerCSSPixel()) { - trackSize = AppUnitsPerCSSPixel(); - } + // Use a minimum 1px for the repeat() track-size. + if (trackSize < AppUnitsPerCSSPixel()) { + trackSize = AppUnitsPerCSSPixel(); } repeatTrackSize = trackSize; } sum += trackSize; } - nscoord gridGap; - float percentSum = 0.0f; - float gridGapPercent; - ResolvePercentSizeParts(aGridGap, percentBasis, &gridGap, &gridGapPercent); + nscoord gridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aSize); if (numTracks > 1) { // Add grid-gaps for all the tracks including the repeat() track. sum += gridGap * (numTracks - 1); - percentSum = gridGapPercent * (numTracks - 1); } // Calculate the max number of tracks that fits without overflow. nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize; - nscoord size = nsLayoutUtils::AddPercents(sum, percentSum); - if (available - size < 0) { + nscoord spaceToFill = available - sum; + if (spaceToFill <= 0) { // "if any number of repetitions would overflow, then 1 repetition" return 1; } - uint32_t numRepeatTracks = 1; - bool exactFit = false; - while (true) { - sum += gridGap + repeatTrackSize; - percentSum += gridGapPercent; - nscoord newSize = nsLayoutUtils::AddPercents(sum, percentSum); - if (newSize <= size) { - // Adding more repeat-tracks won't make forward progress. - return numRepeatTracks; - } - size = newSize; - nscoord remaining = available - size; - exactFit = remaining == 0; - if (remaining >= 0) { - ++numRepeatTracks; - } - if (remaining <= 0) { - break; - } - } - - if (!exactFit && maxFill == NS_UNCONSTRAINEDSIZE) { + // Calculate the max number of tracks that fits without overflow. + div_t q = div(spaceToFill, repeatTrackSize + gridGap); + // The +1 here is for the one repeat track we already accounted for above. + uint32_t numRepeatTracks = q.quot + 1; + if (q.rem != 0 && maxFill == NS_UNCONSTRAINEDSIZE) { // "Otherwise, if the grid container has a definite min size in // the relevant axis, the number of repetitions is the largest possible // positive integer that fulfills that minimum requirement." @@ -1882,13 +1822,6 @@ struct nsGridContainerFrame::Tracks WritingMode aWM, const LogicalSize& aContainerSize); - /** - * Return the intrinsic size by back-computing percentages as: - * IntrinsicSize = SumOfCoordSizes / (1 - SumOfPercentages). - */ - nscoord BackComputedIntrinsicSize(const TrackSizingFunctions& aFunctions, - const nsStyleCoord& aGridGap) const; - nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const { if (MOZ_UNLIKELY(mSizes.IsEmpty())) { @@ -2198,11 +2131,10 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput } /** - * Calculate our track sizes. If the given aContentBox block-axis size is - * unconstrained, it is assigned to the resulting intrinsic block-axis size. + * Calculate our track sizes. */ void CalculateTrackSizes(const Grid& aGrid, - LogicalSize& aContentBox, + const LogicalSize& aContentBox, SizingConstraint aConstraint); /** @@ -2688,7 +2620,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Grid void nsGridContainerFrame::GridReflowInput::CalculateTrackSizes( const Grid& aGrid, - LogicalSize& aContentBox, + const LogicalSize& aContentBox, SizingConstraint aConstraint) { mCols.Initialize(mColFunctions, mGridStyle->mGridColumnGap, @@ -2706,12 +2638,6 @@ nsGridContainerFrame::GridReflowInput::CalculateTrackSizes( mRows.CalculateSizes(*this, mGridItems, mRowFunctions, aContentBox.BSize(mWM), &GridArea::mRows, aConstraint); - if (aContentBox.BSize(mWM) == NS_AUTOHEIGHT) { - aContentBox.BSize(mWM) = - mRows.BackComputedIntrinsicSize(mRowFunctions, mGridStyle->mGridRowGap); - mRows.mGridGap = - ::ResolveToDefiniteSize(mGridStyle->mGridRowGap, aContentBox.BSize(mWM)); - } } /** @@ -3813,7 +3739,7 @@ nsGridContainerFrame::Tracks::Initialize( aFunctions.MinSizingFor(i), aFunctions.MaxSizingFor(i)); } - mGridGap = ::ResolveToDefiniteSize(aGridGap, aContentBoxSize); + mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize); mContentBoxSize = aContentBoxSize; } @@ -3894,8 +3820,7 @@ ContentContribution(const GridItemInfo& aGridItem, PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis)); nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, child, aConstraint, aPercentageBasis, - aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED | - nsLayoutUtils::ADD_PERCENTS, + aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED, aMinSizeClamp); if (size == NS_INTRINSIC_WIDTH_UNKNOWN) { // We need to reflow the child to find its BSize contribution. @@ -3932,15 +3857,7 @@ ContentContribution(const GridItemInfo& aGridItem, LogicalSize availableSize(childWM, availISize, availBSize); size = ::MeasuringReflow(child, aState.mReflowInput, aRC, availableSize, cbSize, iMinSizeClamp, bMinSizeClamp); - nsIFrame::IntrinsicISizeOffsetData offsets = child->IntrinsicBSizeOffsets(); - size += offsets.hMargin; - auto percent = offsets.hPctMargin; - if (availBSize == NS_UNCONSTRAINEDSIZE) { - // We always want to add in percent padding too, unless we already did so - // using a resolved column size above. - percent += offsets.hPctPadding; - } - size = nsLayoutUtils::AddPercents(size, percent); + size += child->GetLogicalUsedMargin(childWM).BStartEnd(childWM); nscoord overflow = size - aMinSizeClamp; if (MOZ_UNLIKELY(overflow > 0)) { nscoord contentSize = child->ContentBSize(childWM); @@ -4045,6 +3962,10 @@ MinSize(const GridItemInfo& aGridItem, return s; } + if (aCache->mPercentageBasis.isNothing()) { + aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem)); + } + // https://drafts.csswg.org/css-grid/#min-size-auto // This calculates the min-content contribution from either a definite // min-width (or min-height depending on aAxis), or the "specified / @@ -4058,7 +3979,8 @@ MinSize(const GridItemInfo& aGridItem, "baseline offset should be zero when not baseline-aligned"); nscoord sz = aGridItem.mBaselineOffset[aAxis] + nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child, - nsLayoutUtils::MIN_ISIZE); + nsLayoutUtils::MIN_ISIZE, + *aCache->mPercentageBasis); const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth : stylePos->mMinHeight; auto unit = style.GetUnit(); @@ -4067,9 +3989,6 @@ MinSize(const GridItemInfo& aGridItem, child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) { // Now calculate the "content size" part and return whichever is smaller. MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE); - if (aCache->mPercentageBasis.isNothing()) { - aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem)); - } sz = std::min(sz, ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache->mPercentageBasis, nsLayoutUtils::MIN_ISIZE, @@ -5097,36 +5016,6 @@ nsGridContainerFrame::Tracks::AlignJustifyContent( MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?"); } -nscoord -nsGridContainerFrame::Tracks::BackComputedIntrinsicSize( - const TrackSizingFunctions& aFunctions, - const nsStyleCoord& aGridGap) const -{ - // Sum up the current sizes (where percentage tracks were treated as 'auto') - // in 'size'. - nscoord size = 0; - for (size_t i = 0, len = mSizes.Length(); i < len; ++i) { - size += mSizes[i].mBase; - } - - // Add grid-gap contributions to 'size' and calculate a 'percent' sum. - float percent = 0.0f; - size_t numTracks = mSizes.Length(); - if (numTracks > 1) { - const size_t gridGapCount = numTracks - 1; - nscoord gridGapLength; - float gridGapPercent; - if (::GetPercentSizeParts(aGridGap, &gridGapLength, &gridGapPercent)) { - percent = gridGapCount * gridGapPercent; - } else { - gridGapLength = aGridGap.ToLength(); - } - size += gridGapCount * gridGapLength; - } - - return std::max(0, nsLayoutUtils::AddPercents(size, percent)); -} - void nsGridContainerFrame::LineRange::ToPositionAndLength( const nsTArray& aTrackSizes, nscoord* aPos, nscoord* aLength) const @@ -6292,7 +6181,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, LogicalSize computedSize(wm, computedISize, computedBSize); nscoord consumedBSize = 0; - nscoord bSize; + nscoord bSize = 0; if (!prevInFlow) { Grid grid; grid.PlaceGridItems(gridReflowInput, aReflowInput.ComputedMinSize(), @@ -6300,7 +6189,12 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, gridReflowInput.CalculateTrackSizes(grid, computedSize, SizingConstraint::eNoConstraint); - bSize = computedSize.BSize(wm); + // Note: we can't use GridLineEdge here since we haven't calculated + // the rows' mPosition yet (happens in AlignJustifyContent below). + for (const auto& sz : gridReflowInput.mRows.mSizes) { + bSize += sz.mBase; + } + bSize += gridReflowInput.mRows.SumOfGridGaps(); } else { consumedBSize = GetConsumedBSize(); gridReflowInput.InitializeForContinuation(this, consumedBSize); @@ -6699,8 +6593,14 @@ nsGridContainerFrame::IntrinsicISize(nsRenderingContext* aRenderingContext, state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions, NS_UNCONSTRAINEDSIZE, &GridArea::mCols, constraint); - return state.mCols.BackComputedIntrinsicSize(state.mColFunctions, - state.mGridStyle->mGridColumnGap); + state.mCols.mGridGap = + nsLayoutUtils::ResolveGapToLength(state.mGridStyle->mGridColumnGap, + NS_UNCONSTRAINEDSIZE); + nscoord length = 0; + for (const TrackSize& sz : state.mCols.mSizes) { + length += sz.mBase; + } + return length + state.mCols.SumOfGridGaps(); } nscoord diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index ec3568483..57f5c460c 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -25,6 +25,7 @@ #include "CaretAssociationHint.h" #include "FrameProperties.h" +#include "LayoutConstants.h" #include "mozilla/layout/FrameChildList.h" #include "mozilla/Maybe.h" #include "mozilla/WritingModes.h" @@ -130,30 +131,12 @@ typedef uint32_t nsSplittableType; #define NS_FRAME_IS_NOT_SPLITTABLE(type)\ (0 == ((type) & NS_FRAME_SPLITTABLE)) -#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN - //---------------------------------------------------------------------- #define NS_SUBTREE_DIRTY(_frame) \ (((_frame)->GetStateBits() & \ (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0) -/** - * Constant used to indicate an unconstrained size. - * - * @see #Reflow() - */ -#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE - -#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE -#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE -// +1 is to avoid clamped huge margin values being processed as auto margins -#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1) -#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE -// NOTE: there are assumptions all over that these have the same value, namely NS_UNCONSTRAINEDSIZE -// if any are changed to be a value other than NS_UNCONSTRAINEDSIZE -// at least update AdjustComputedHeight/Width and test ad nauseum - // 1 million CSS pixels less than our max app unit measure. // For reflowing with an "infinite" available inline space per [css-sizing]. // (reflowing with an NS_UNCONSTRAINEDSIZE available inline size isn't allowed @@ -2050,23 +2033,27 @@ public: /** * Return the horizontal components of padding, border, and margin * that contribute to the intrinsic width that applies to the parent. + * @param aPercentageBasis the percentage basis to use for padding/margin - + * i.e. the Containing Block's inline-size */ struct IntrinsicISizeOffsetData { nscoord hPadding, hBorder, hMargin; - float hPctPadding, hPctMargin; IntrinsicISizeOffsetData() : hPadding(0), hBorder(0), hMargin(0) - , hPctPadding(0.0f), hPctMargin(0.0f) {} }; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() = 0; + virtual IntrinsicISizeOffsetData + IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) = 0; /** * Return the bsize components of padding, border, and margin * that contribute to the intrinsic width that applies to the parent. + * @param aPercentageBasis the percentage basis to use for padding/margin - + * i.e. the Containing Block's inline-size */ - IntrinsicISizeOffsetData IntrinsicBSizeOffsets(); + IntrinsicISizeOffsetData + IntrinsicBSizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE); virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0; diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 2049f70e8..07db6d3dd 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1499,7 +1499,7 @@ CSS_PROP_COLUMN( CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_NONNEGATIVE, "", - VARIANT_HL | VARIANT_NORMAL | VARIANT_CALC, + VARIANT_HLP | VARIANT_NORMAL | VARIANT_CALC, nullptr, offsetof(nsStyleColumn, mColumnGap), eStyleAnimType_Coord) diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index c8182b8f1..b257c6bb5 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -3495,7 +3495,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn uint32_t mColumnCount; // [reset] see nsStyleConsts.h nsStyleCoord mColumnWidth; // [reset] coord, auto - nsStyleCoord mColumnGap; // [reset] coord, normal + nsStyleCoord mColumnGap; // [reset] | normal mozilla::StyleComplexColor mColumnRuleColor; // [reset] uint8_t mColumnRuleStyle; // [reset] diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 272931c15..c75f7b498 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -1438,7 +1438,7 @@ var gCSSProperties = { inherited: false, type: CSS_TYPE_LONGHAND, initial_values: [ "normal", "1em", "calc(-2em + 3em)" ], - other_values: [ "2px", "4em", + other_values: [ "2px", "1em", "4em", "3%", "calc(3%)", "calc(1em - 3%)", "calc(2px)", "calc(-2px)", "calc(0px)", @@ -1448,7 +1448,7 @@ var gCSSProperties = { "calc(25px*3)", "calc(3*25px + 5em)", ], - invalid_values: [ "3%", "-1px", "4" ] + invalid_values: [ "-3%", "-1px", "4" ] }, "-moz-column-gap": { domProp: "MozColumnGap", diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 316a96613..dea82ea59 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -796,12 +796,12 @@ nsTableCellFrame::GetPrefISize(nsRenderingContext *aRenderingContext) } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsTableCellFrame::IntrinsicISizeOffsets() +nsTableCellFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) { - IntrinsicISizeOffsetData result = nsContainerFrame::IntrinsicISizeOffsets(); + IntrinsicISizeOffsetData result = + nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis); result.hMargin = 0; - result.hPctMargin = 0; WritingMode wm = GetWritingMode(); result.hBorder = GetBorderWidth(wm).IStartEnd(wm); diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index 6717e1b70..240809850 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -118,7 +118,8 @@ public: virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData IntrinsicISizeOffsets(nscoord aPercentageBasis = + NS_UNCONSTRAINEDSIZE) override; virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index b9b6ca5fe..272a77406 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1564,16 +1564,15 @@ nsTableFrame::GetPrefISize(nsRenderingContext *aRenderingContext) } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsTableFrame::IntrinsicISizeOffsets() +nsTableFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) { - IntrinsicISizeOffsetData result = nsContainerFrame::IntrinsicISizeOffsets(); + IntrinsicISizeOffsetData result = + nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis); result.hMargin = 0; - result.hPctMargin = 0; if (IsBorderCollapse()) { result.hPadding = 0; - result.hPctPadding = 0; WritingMode wm = GetWritingMode(); LogicalMargin outerBC = GetIncludedOuterBCBorder(wm); diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 7e56c28c1..c7b92d387 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -324,7 +324,8 @@ public: // border to the results of these functions. virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData IntrinsicISizeOffsets(nscoord aPercentageBasis = + NS_UNCONSTRAINEDSIZE) override; virtual mozilla::LogicalSize ComputeSize(nsRenderingContext* aRenderingContext, -- cgit v1.2.3 From 30d65c382f9404a31c46c9976a3b170273fd9509 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 28 Sep 2019 23:43:36 -0400 Subject: Issue #1230 - Part 3: Update Reftests Ref: 1434478 part 7 - Update tests and enable some previously temporarily disabled Grid reftests from bug 1427608. --- layout/reftests/bugs/403519-2-ref.html | 2 +- .../grid-auto-min-sizing-definite-001-ref.html | 51 +++++++++----- ...to-min-sizing-min-content-min-size-002-ref.html | 2 +- ...to-min-sizing-min-content-min-size-004-ref.html | 2 +- .../grid-auto-min-sizing-percent-001-ref.html | 10 +-- ...d-auto-min-sizing-transferred-size-002-ref.html | 2 +- ...d-auto-min-sizing-transferred-size-004-ref.html | 2 +- .../css-grid/grid-item-sizing-percent-003-ref.html | 78 +++++++++++----------- .../css-grid/grid-item-sizing-percent-004-ref.html | 78 +++++++++++----------- .../css-grid/grid-percent-grid-gap-001-ref.html | 16 ++--- .../grid-repeat-auto-fill-fit-002-ref.html | 6 +- .../writing-mode/1174450-intrinsic-sizing-ref.html | 16 ++--- 12 files changed, 143 insertions(+), 122 deletions(-) (limited to 'layout') diff --git a/layout/reftests/bugs/403519-2-ref.html b/layout/reftests/bugs/403519-2-ref.html index e00fb5e24..72176a89a 100644 --- a/layout/reftests/bugs/403519-2-ref.html +++ b/layout/reftests/bugs/403519-2-ref.html @@ -17,7 +17,7 @@ table { - + diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html index 8858b4ea8..f2c76f78b 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html @@ -65,32 +65,49 @@ b40 { .h.r { height: 42px; width: 42px; - /* This margin-left is 20% of 98px-wide grid area */ - margin-left: 19.6px; - /* This padding-bottom is 10% of 98px wide grid area */ - /* This padding-left is 30% of 98px wide grid area */ - padding: 1px 3px 9.8px 29.4px; + /* 49px is the percentage basis, i.e. the column size */ + margin-left: calc(0.2 * 49px); + padding: 1px 3px calc(0.1 * 49px) calc(0.3 * 49px); } .v.r { height: 42px; width: 42px; - /* This margin-left is 20% of 54px-wide grid area */ - margin-left: 10.8px; - /* This padding-bottom is 10% of 54px wide grid area */ - /* This padding-left is 30% of 54px wide grid area */ - padding: 1px 3px 5.4px 16.2px; + /* 27px is the percentage basis, i.e. the column size */ + margin-left: calc(0.2 * 27px); + padding: 1px 3px calc(0.1 * 27px) calc(0.3 * 27px); } .r { position:relative; } +.t4 { width: 49px; + height: calc(10px /* item min-height */ + + 7px /* item margin-top */ + + 1px /* item padding-top */ + + 1px /* item border-top */ + + calc(0.5 * 49px) /* item margin-bottom */ + + calc(0.1 * 49px) /* item padding-bottom */); + } + .t6 { width:46px; } -.t8 { width:118px; height: 102.5px; } +.t8 { width: 27px; + height: calc(30px /* item min-height */ + + 7px /* item margin-top */ + + 3px /* item padding-top */ + + 1px /* item border-top */ + + calc(0.5 * 27px) /* item margin-bottom */ + + calc(0.1 * 27px) /* item padding-bottom */); + } xx { display: block; background: lime; - padding:32px 32px 16px 32px; - margin: 0 0 32px 16px; + padding: 32px 32px calc(0.2 * 32px) calc(0.4 * 32px); + margin: 0 0 calc(0.4 * 32px) calc(0.2 * 32px); +} +.t9, .t10 { + position: relative; + z-index: 1; + grid: calc(32px + calc(0.4 * 32px) + calc(0.2 * 32px)) 0 / 32px; } @@ -100,15 +117,15 @@ xx {
-
+

-
+
-
-
+
+
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html index 35f596928..183f00e24 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html @@ -36,7 +36,7 @@ var coltest = [ "min-height:40%", "min-height:40%; max-width:30px" ]; var results = [ -"360px", "360px", "360px", "24px", "24px", "360px", "80px", "24px", "24px", "24px", +"24px", "24px", "24px", "24px", "24px", "24px", "80px", "24px", "24px", "24px", "24px", "24px", "24px" ]; var item_width = [ diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html index caef8b031..6533c97b6 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html @@ -36,7 +36,7 @@ var rowtest = [ "min-width:80%; max-height:20px", "min-width:50%", "margin-left: 50px; width:50%" ]; var results = [ -"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "24px/52px" +"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "312px/52px" ]; var item_height = [ "0", "0", "0", "0", "0", "0", "12px", "20px", "20px", "24px", "312px" diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html index fd2302add..d435f8f3e 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html @@ -54,9 +54,9 @@ br { clear:both; } .c10 { grid-template-columns: minmax(10px,0) 1fr; } #px-border .c10 { grid-template-columns: minmax(30px,0) 1fr; } -#percent-border .c100 { grid-template-columns: 111px 0; } -#percent-border .c100calc100 { grid-template-columns: 100px 11px; } -#percent-border .c10 { grid-template-columns: minmax(11px,0) 0; } +#percent-border .c100 { grid-template-columns: 100px 0; } +#percent-border .c100calc100 { grid-template-columns: 100px 10px; } +#percent-border .c10 { grid-template-columns: minmax(10px,0) 0; } #percent-border .c100100 { grid-template-columns: minmax(100px,0) 150px; } #percent-border .c200 { grid-template-columns: 250px; } @@ -99,7 +99,7 @@ var grids = [ "grid c100", "grid c100", "grid", -"grid c200", +"grid c100", "grid c10", "grid c100", "grid c100", @@ -110,7 +110,7 @@ var grids = [ "grid c100", "grid c100", "grid", -"grid c200", +"grid c100", "grid c10", "grid c100", "grid c100", diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html index 8dcdd563b..528d63bc7 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html @@ -36,7 +36,7 @@ var coltest = [ "min-height:40%", "min-height:40%; max-width:30px" ]; var results = [ -"360px", "360px", "360px", "24px", "24px", "360px", "80px", "24px", "20px", "24px", +"360px", "0px", "0px", "0px", "24px", "360px", "80px", "24px", "20px", "24px", "6px", "24px", "24px" ]; var item_width = [ diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html index 36a2d4920..4eb623b7d 100644 --- a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html @@ -36,7 +36,7 @@ var rowtest = [ "min-width:80%; max-height:20px", "min-width:50%", "margin-left: 50px; width:50%" ]; var results = [ -"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "24px/52px" +"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "312px/52px" ]; var item_height = [ "0", "0", "0", "0", "0", "0", "12px", "20px", "20px", "24px", "312px" diff --git a/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html b/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html index fb4d15ff8..a55dcc989 100644 --- a/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html +++ b/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html @@ -69,67 +69,67 @@ a {
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html b/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html index 51f71e662..96365b468 100644 --- a/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html +++ b/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html @@ -62,71 +62,71 @@ a {
-
-
-
-
+
+
+
+
-
-
-
+
+
+

-
-
-
-
+
+
+
+
-
-
-
+
+
+

-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html b/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html index 945b43b52..7ad85e1e5 100644 --- a/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html +++ b/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html @@ -65,7 +65,7 @@ br { clear: both; }
-
+
@@ -74,7 +74,7 @@ br { clear: both; }
-
+
@@ -141,12 +141,12 @@ br { clear: both; }
-
-
- - - - +
+
+ + + +
diff --git a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html index a404a0905..682e0ca38 100644 --- a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html @@ -83,12 +83,16 @@ fill,fit { .zero-progress { grid-row-gap: calc(10px - 1%); - grid-template-rows: [a] 10px repeat(4, [b] minmax(0,auto) [c]) [d]; + grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d]; } .w50.zero-progress { grid-row-gap: calc(10px - 1%); grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d]; } +.mw50.zero-progress { + grid-row-gap: calc(10px - 1%); + grid-template-rows: [a] 10px repeat(4, [b] 0 [c]) [d]; +} diff --git a/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html b/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html index 629c0a917..3645fa006 100644 --- a/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html +++ b/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html @@ -13,20 +13,20 @@ div.v, div.h { display: block; position: relative; border: 1px dashed silver; - width:92px; - height:60px; + width:74px; + height:24px; } div.h { - width:124px; - height:98px; + width:62px; + height:61.2px; } .h span { - margin: 7px 13px 62px 25px; - padding: 1px 3px 12px 37px; + margin: 7px 13px 32px 12px; + padding: 1px 3px 6px 19px; } .v span { - margin: 7px 13px 30px 12px; - padding: 1px 3px 6px 18px; + margin: 7px 13px 30px 5px; + padding: 1px 3px 2px 7px; } span { -- cgit v1.2.3 From afc187cc3f907947453b428f857acf16b2b0774e Mon Sep 17 00:00:00 2001 From: athenian200 Date: Tue, 1 Oct 2019 06:07:31 -0500 Subject: MoonchildProductions#1251 - Part 1: Restore initial Solaris support, fixed up. Compared with what Pale Moon had for Solaris originally, this is mostly the same zero point I started patching from, but I've made the following changes here after reviewing all this initial code I never looked at closely before. 1. In package-manifest.in for both Basilisk and Pale Moon, I've made the SPARC code for libfreebl not interefere with the x86 code, use the proper build flags, and also updated it to allow a SPARC64 build which is more likely to be used than the 32-bit SPARC code we had there. 2. See Mozilla bug #832272 and the old rules.mk patch from around Firefox 30 in oracle/solaris-userland. I believe they screwed up NSINSTALL on Solaris when they were trying to streamline the NSS buildsystem, because they started having unexplained issues with it around that time after Firefox 22 that they never properly resolved until Mozilla began building NSS with gyp files. I'm actually not even sure how relevant the thing they broke actually is to Solaris at this point, bug 665509 is so old it predates Firefox itself and goes back to the Mozilla suite days. I believe $(INSTALL) -t was wrong, and they meant $(NSINSTALL) -t because that makes more sense and is closer to what was there originally. It's what they have for WINNT, and it's possible a fix more like that could serve for Solaris as well. Alternatively, we could get rid of all these half-broken Makefiles and start building NSS with gyp files like Mozilla did. 3. I've completely cut out support for the Sun compiler and taken into account the reality that everyone builds Firefox (and therefore its forks) with GCC now on Solaris. This alone helped clean up a lot of the uglier parts of the code. 4. I've updated all remaining SOLARIS build flags to the newer XP_SOLARIS, because the SOLARIS flag is no longer set when building Solaris. 5. I've confirmed the workaround in gtxFontconfigFonts.cpp is no longer necessary. The Solaris people got impatient about implementing a half-baked patch for a fontconfig feature that wasn't ready yet back in 2009, and somehow convinced Mozilla to patch their software to work around it when really they should have just fixed or removed their broken fontconfig patch. The feature they wanted has since been implemented properly, and no version of Solaris still uses the broken patch that required this fix. If anyone had ever properly audited this code, it would have been removed a long time ago. --- layout/style/nsRuleNode.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'layout') diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 08400635b..a0f65c069 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -67,6 +67,9 @@ #define alloca _alloca #endif #endif +#ifdef XP_SOLARIS +#include +#endif using std::max; using std::min; -- cgit v1.2.3 From 145527207538b6ee1018cb77e6705912c29f8a9f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Nov 2019 22:39:03 +0100 Subject: Issue #146 - Part 1: Draw each table's background on their own display list items. This patch does the following things: 1. Creates nsDisplayTableBorderCollapse that draws all collapse border of tables. 2. Stops the use of nsDisplayTableBorderBackground. 3. Lets column and column group frames generate display items. 4. When traversing the table, also traverses the column and column group frames. 5. For each type of table frame (col group, col, row group, row and cell), draws their own background. --- layout/base/nsDisplayItemTypesList.h | 1 + layout/base/nsDisplayList.cpp | 9 +- layout/base/nsDisplayList.h | 3 +- layout/tables/nsTableCellFrame.cpp | 103 ++++++------- layout/tables/nsTableColFrame.cpp | 8 + layout/tables/nsTableColFrame.h | 5 +- layout/tables/nsTableColGroupFrame.cpp | 8 + layout/tables/nsTableColGroupFrame.h | 5 +- layout/tables/nsTableFrame.cpp | 268 ++++++++++++++++++--------------- layout/tables/nsTableFrame.h | 1 - layout/tables/nsTableRowFrame.cpp | 16 +- layout/tables/nsTableRowGroupFrame.cpp | 13 +- layout/tables/nsTableWrapperFrame.cpp | 6 +- 13 files changed, 223 insertions(+), 223 deletions(-) (limited to 'layout') diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h index 9865395a7..d24f6f38f 100644 --- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -59,6 +59,7 @@ DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION) DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_GROUP_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_BACKGROUND) +DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE) DECLARE_DISPLAY_ITEM_TYPE(TEXT) DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW) DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index e22230b41..744153831 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2631,11 +2631,16 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil const nsRect& aBackgroundRect, nsDisplayList* aList, bool aAllowWillPaintBorderOptimization, - nsStyleContext* aStyleContext) + nsStyleContext* aStyleContext, + const nsRect& aBackgroundOriginRect) { nsStyleContext* bgSC = aStyleContext; const nsStyleBackground* bg = nullptr; nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame); + nsRect bgOriginRect = bgRect; + if (!aBackgroundOriginRect.IsEmpty()) { + bgOriginRect = aBackgroundOriginRect + aBuilder->ToReferenceFrame(aFrame); + } nsPresContext* presContext = aFrame->PresContext(); bool isThemed = aFrame->IsThemed(); if (!isThemed) { @@ -2744,7 +2749,7 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil nsDisplayList thisItemList; nsDisplayBackgroundImage* bgItem = - new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgRect, bg); + new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgOriginRect, bg); if (bgItem->ShouldFixToViewport(aBuilder)) { thisItemList.AppendNewToTop( diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index c81d34fac..9431e2cc0 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2737,7 +2737,8 @@ public: const nsRect& aBackgroundRect, nsDisplayList* aList, bool aAllowWillPaintBorderOptimization = true, - nsStyleContext* aStyleContext = nullptr); + nsStyleContext* aStyleContext = nullptr, + const nsRect& aBackgroundOriginRect = nsRect()); virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index dea82ea59..bac8d387f 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -484,70 +484,51 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); - if (IsVisibleInSelection(aBuilder)) { - nsTableFrame* tableFrame = GetTableFrame(); - int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? - StyleTableBorder()->mEmptyCells - : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; - // take account of 'empty-cells' - if (StyleVisibility()->IsVisible() && - (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { - // display outset box-shadows if we need to. - bool hasBoxShadow = !!StyleEffects()->mBoxShadow; - if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); - } - - // display background if we need to. - if (aBuilder->IsForEventDelivery() || - !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) { - if (!tableFrame->IsBorderCollapse()) { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, - this, - GetRectRelativeToSelf(), - aLists.BorderBackground()); - } else if (aBuilder->IsAtRootOfPseudoStackingContext() || - aBuilder->IsForEventDelivery()) { - // The cell background was not painted by the nsTablePainter, - // so we need to do it. We have special background processing here - // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline - nsDisplayTableItem* item = - new (aBuilder) nsDisplayTableCellBackground(aBuilder, this); - aLists.BorderBackground()->AppendNewToTop(item); - item->UpdateForFrameBackground(this); - } else { - // The nsTablePainter will paint our background. Make sure it - // knows if we're background-attachment:fixed. - nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); - if (currentItem) { - currentItem->UpdateForFrameBackground(this); - } - } - } - - // display inset box-shadows if we need to. - if (hasBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this)); - } - - // display borders if we need to - ProcessBorders(tableFrame, aBuilder, aLists); - - // and display the selection border if we need to - if (IsSelected()) { - aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection, - "TableCellSelection", - nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); - } + nsTableFrame* tableFrame = GetTableFrame(); + int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? + StyleTableBorder()->mEmptyCells + : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; + // take account of 'empty-cells' + if (StyleVisibility()->IsVisible() && + (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { + // display outset box-shadows if we need to. + bool hasBoxShadow = !!StyleEffects()->mBoxShadow; + if (hasBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); + } + + // display background if we need to. + if (aBuilder->IsForEventDelivery() || + !StyleBackground()->IsTransparent() || + StyleDisplay()->mAppearance) { + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, + this, + GetRectRelativeToSelf(), + aLists.BorderBackground()); + } + + // display inset box-shadows if we need to. + if (hasBoxShadow) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this)); + } + + // display borders if we need to + ProcessBorders(tableFrame, aBuilder, aLists); + + // and display the selection border if we need to + if (IsSelected()) { + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) + nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection, + "TableCellSelection", + nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); } - - // the 'empty-cells' property has no effect on 'outline' - DisplayOutline(aBuilder, aLists); } + // the 'empty-cells' property has no effect on 'outline' + DisplayOutline(aBuilder, aLists); + // Push a null 'current table item' so that descendant tables can't // accidentally mess with our table nsAutoPushCurrentTableItem pushTableItem; diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp index 8f449c3d9..54b03522b 100644 --- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -108,6 +108,14 @@ nsTableColFrame::Reflow(nsPresContext* aPresContext, NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); } +void +nsTableColFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); +} + int32_t nsTableColFrame::GetSpan() { return StyleTable()->mSpan; diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h index e95fe76b1..fb989061f 100644 --- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -59,12 +59,9 @@ public: const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; - /** - * Table columns never paint anything, nor receive events. - */ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) override {} + const nsDisplayListSet& aLists) override; /** * Get the "type" of the frame diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp index ff8879a0b..6ee7f0b24 100644 --- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -383,6 +383,14 @@ nsTableColGroupFrame::Reflow(nsPresContext* aPresContext, NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); } +void +nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); +} + nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() { return GetNextColumn(nullptr); diff --git a/layout/tables/nsTableColGroupFrame.h b/layout/tables/nsTableColGroupFrame.h index 2a25fdc44..b3dfb94e7 100644 --- a/layout/tables/nsTableColGroupFrame.h +++ b/layout/tables/nsTableColGroupFrame.h @@ -43,12 +43,9 @@ public: return static_cast(parent); } - /** - * ColGroups never paint anything, nor receive events. - */ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) override {} + const nsDisplayListSet& aLists) override; /** A colgroup can be caused by three things: * 1) An element with table-column-group display diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 272a77406..b5cd3b487 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1131,6 +1131,42 @@ nsDisplayTableItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); } +// A display item that draws all collapsed borders for a table. +class nsDisplayTableBorderCollapse : public nsDisplayTableItem { +public: + nsDisplayTableBorderCollapse(nsDisplayListBuilder* aBuilder, + nsTableFrame* aFrame) + : nsDisplayTableItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayTableBorderCollapse); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayTableBorderCollapse() { + MOZ_COUNT_DTOR(nsDisplayTableBorderCollapse); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) override; + NS_DISPLAY_DECL_NAME("TableBorderCollapse", TYPE_TABLE_BORDER_COLLAPSE) +}; + +void +nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) +{ + nsPoint pt = ToReferenceFrame(); + DrawTarget* drawTarget = aCtx->GetDrawTarget(); + + gfxPoint devPixelOffset = + nsLayoutUtils::PointToGfxPoint(pt, mFrame->PresContext()->AppUnitsPerDevPixel()); + + AutoRestoreTransform autoRestoreTransform(drawTarget); + drawTarget->SetTransform( + drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); + + static_cast(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt); +} + class nsDisplayTableBorderBackground : public nsDisplayTableItem { public: nsDisplayTableBorderBackground(nsDisplayListBuilder* aBuilder, @@ -1150,20 +1186,6 @@ public: NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND) }; -#ifdef DEBUG -static bool -IsFrameAllowedInTable(nsIAtom* aType) -{ - return IS_TABLE_CELL(aType) || - nsGkAtoms::tableRowFrame == aType || - nsGkAtoms::tableRowGroupFrame == aType || - nsGkAtoms::scrollFrame == aType || - nsGkAtoms::tableFrame == aType || - nsGkAtoms::tableColFrame == aType || - nsGkAtoms::tableColGroupFrame == aType; -} -#endif - void nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) @@ -1175,25 +1197,6 @@ nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder, nsDisplayTableItemGeometry::UpdateDrawResult(this, result); } -static int32_t -GetTablePartRank(nsDisplayItem* aItem) -{ - nsIAtom* type = aItem->Frame()->GetType(); - if (type == nsGkAtoms::tableFrame) - return 0; - if (type == nsGkAtoms::tableRowGroupFrame) - return 1; - if (type == nsGkAtoms::tableRowFrame) - return 2; - return 3; -} - -static bool CompareByTablePartRank(nsDisplayItem* aItem1, nsDisplayItem* aItem2, - void* aClosure) -{ - return GetTablePartRank(aItem1) <= GetTablePartRank(aItem2); -} - /* static */ void nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) @@ -1206,31 +1209,73 @@ nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, // stacking context, in which case the child won't use its passed-in // BorderBackground list anyway. It does affect cell borders though; this // lets us get cell borders into the nsTableFrame's BorderBackground list. + for (nsIFrame* kid : aFrame->GetChildList(kColGroupList)) { + aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); + } + for (nsIFrame* kid : aFrame->PrincipalChildList()) { aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); } } +static void +PaintRowBackground(nsTableRowFrame* aRow, + nsIFrame* aFrame, + nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists, + const nsPoint& aOffset = nsPoint()) +{ + // Compute background rect by iterating all cell frame. + for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { + auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, + aLists.BorderBackground(), + true, nullptr, + aFrame->GetRectRelativeToSelf()); + } +} + +static void +PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup, + nsIFrame* aFrame, + nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists) +{ + for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { + PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition()); + } +} + +static void +PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, + nsIFrame* aFrame, + nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists, + const nsTArray& aColIdx, + const nsPoint& aOffset) +{ + for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { + for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + int32_t curColIdx; + cell->GetColIndex(curColIdx); + if (aColIdx.Contains(curColIdx)) { + auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + row->GetNormalPosition() + aOffset; + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, + aLists.BorderBackground(), + true, nullptr, + aFrame->GetRectRelativeToSelf()); + } + } + } +} + /* static */ void nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, - nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal) { - nsDisplayList eventsBorderBackground; - // If we need to sort the event backgrounds, then we'll put descendants' - // display items into their own set of lists. - bool sortEventBackgrounds = aDisplayItem && aBuilder->IsForEventDelivery(); - nsDisplayListCollection separatedCollection; - const nsDisplayListSet* lists = sortEventBackgrounds ? &separatedCollection : &aLists; - - nsAutoPushCurrentTableItem pushTableItem; - if (aDisplayItem) { - pushTableItem.Push(aBuilder, aDisplayItem); - } - if (aFrame->IsVisibleForPainting(aBuilder)) { nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); // currentItem may be null, when none of the table parts have a @@ -1242,72 +1287,79 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, // Paint the outset box-shadows for the table frames bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr; if (hasBoxShadow) { - lists->BorderBackground()->AppendNewToTop( + aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame)); } - // Create dedicated background display items per-frame when we're - // handling events. - // XXX how to handle collapsed borders? - if (aBuilder->IsForEventDelivery()) { + if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { + nsTableRowGroupFrame* rowGroup = static_cast(aFrame); + PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); + } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) { + nsTableRowFrame* row = static_cast(aFrame); + PaintRowBackground(row, aFrame, aBuilder, aLists); + } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) { + // Compute background rect by iterating all cell frame. + nsTableColGroupFrame* colGroup = static_cast(aFrame); + // Collecting column index. + AutoTArray colIdx; + for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { + colIdx.AppendElement(col->GetColIndex()); + } + + nsTableFrame* table = colGroup->GetTableFrame(); + RowGroupArray rowGroups; + table->OrderRowGroups(rowGroups); + for (nsTableRowGroupFrame* rowGroup : rowGroups) { + auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition(); + PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); + } + } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) { + // Compute background rect by iterating all cell frame. + nsTableColFrame* col = static_cast(aFrame); + AutoTArray colIdx; + colIdx.AppendElement(col->GetColIndex()); + + nsTableFrame* table = col->GetTableFrame(); + RowGroupArray rowGroups; + table->OrderRowGroups(rowGroups); + for (nsTableRowGroupFrame* rowGroup : rowGroups) { + auto offset = rowGroup->GetNormalPosition() - + col->GetNormalPosition() - + col->GetTableColGroupFrame()->GetNormalPosition(); + PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); + } + } else { nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, aFrame->GetRectRelativeToSelf(), - lists->BorderBackground()); + aLists.BorderBackground()); } // Paint the inset box-shadows for the table frames if (hasBoxShadow) { - lists->BorderBackground()->AppendNewToTop( + aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame)); } } - aTraversal(aBuilder, aFrame, aDirtyRect, *lists); + aTraversal(aBuilder, aFrame, aDirtyRect, aLists); - if (sortEventBackgrounds) { - // Ensure that the table frame event background goes before the - // table rowgroups event backgrounds, before the table row event backgrounds, - // before everything else (cells and their blocks) - separatedCollection.BorderBackground()->Sort(CompareByTablePartRank, nullptr); - separatedCollection.MoveTo(aLists); + if (aFrame->IsVisibleForPainting(aBuilder)) { + if (aFrame->GetType() == nsGkAtoms::tableFrame) { + nsTableFrame* table = static_cast(aFrame); + // In the collapsed border model, overlay all collapsed borders. + if (table->IsBorderCollapse()) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table)); + } else { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBorder(aBuilder, table)); + } + } } aFrame->DisplayOutline(aBuilder, aLists); } -static bool -AnyTablePartHasBorderOrBackground(nsIFrame* aStart, nsIFrame* aEnd) -{ - for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) { - NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type"); - - if (FrameHasBorderOrBackground(f)) - return true; - - nsTableCellFrame *cellFrame = do_QueryFrame(f); - if (cellFrame) - continue; - - if (AnyTablePartHasBorderOrBackground(f->PrincipalChildList().FirstChild(), nullptr)) - return true; - } - - return false; -} - -static void -UpdateItemForColGroupBackgrounds(nsDisplayTableItem* item, - const nsFrameList& aFrames) { - for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) { - nsTableColGroupFrame* cg = static_cast(e.get()); - item->UpdateForFrameBackground(cg); - for (nsTableColFrame* colFrame = cg->GetFirstColumn(); colFrame; - colFrame = colFrame->GetNextCol()) { - item->UpdateForFrameBackground(colFrame); - } - } -} - // table paint code is concerned primarily with borders and bg color // SEC: TODO: adjust the rect for captions void @@ -1317,35 +1369,7 @@ nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, { DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255)); - nsDisplayTableItem* item = nullptr; - if (IsVisibleInSelection(aBuilder)) { - nsMargin deflate = GetDeflationForBackground(PresContext()); - if (StyleVisibility()->IsVisible()) { - // If 'deflate' is (0,0,0,0) then we can paint the table background - // in its own display item, so do that to take advantage of - // opacity and visibility optimizations - if (deflate == nsMargin(0, 0, 0, 0)) { - DisplayBackgroundUnconditional(aBuilder, aLists, false); - } - } - - // This background is created if any of the table parts are visible, - // or if we're doing event handling (since DisplayGenericTablePart - // needs the item for the |sortEventBackgrounds|-dependent code). - // Specific visibility decisions are delegated to the table background - // painter, which handles borders and backgrounds for the table. - if (aBuilder->IsForEventDelivery() || - AnyTablePartHasBorderOrBackground(this, GetNextSibling()) || - AnyTablePartHasBorderOrBackground(mColGroups.FirstChild(), nullptr)) { - item = new (aBuilder) nsDisplayTableBorderBackground(aBuilder, this, - deflate != nsMargin(0, 0, 0, 0)); - aLists.BorderBackground()->AppendNewToTop(item); - } - } - DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); - if (item) { - UpdateItemForColGroupBackgrounds(item, mColGroups); - } + DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); } nsMargin diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index c7b92d387..d4b6d88a7 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -250,7 +250,6 @@ public: nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, - nsDisplayTableItem* aDisplayItem, DisplayGenericTablePartTraversal aTraversal = GenericTraversal); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 1b6051ef2..dc053c991 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -605,21 +605,7 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - nsDisplayTableItem* item = nullptr; - if (IsVisibleInSelection(aBuilder)) { - bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); - if (isRoot) { - // This background is created regardless of whether this frame is - // visible or not. Visibility decisions are delegated to the - // table background painter. - // We would use nsDisplayGeneric for this rare case except that we - // need the background to be larger than the row frame in some - // cases. - item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this); - aLists.BorderBackground()->AppendNewToTop(item); - } - } - nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 8f014b204..943bdf50b 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -249,19 +249,8 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - nsDisplayTableItem* item = nullptr; - if (IsVisibleInSelection(aBuilder)) { - bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); - if (isRoot) { - // This background is created regardless of whether this frame is - // visible or not. Visibility decisions are delegated to the - // table background painter. - item = new (aBuilder) nsDisplayTableRowGroupBackground(aBuilder, this); - aLists.BorderBackground()->AppendNewToTop(item); - } - } nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, - aLists, item, DisplayRows); + aLists, DisplayRows); } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableWrapperFrame.cpp b/layout/tables/nsTableWrapperFrame.cpp index f0b6d1512..da71375d5 100644 --- a/layout/tables/nsTableWrapperFrame.cpp +++ b/layout/tables/nsTableWrapperFrame.cpp @@ -190,7 +190,11 @@ nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // Now we have to sort everything by content order, since the caption // may be somewhere inside the table - set.SortAllByContentOrder(GetContent()); + set.BlockBorderBackgrounds()->SortByContentOrder(GetContent()); + set.Floats()->SortByContentOrder(GetContent()); + set.Content()->SortByContentOrder(GetContent()); + set.PositionedDescendants()->SortByContentOrder(GetContent()); + set.Outlines()->SortByContentOrder(GetContent()); set.MoveTo(aLists); } -- cgit v1.2.3 From 0de40040f006c493feeff7d688c169b904b8a22e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Nov 2019 23:07:40 +0100 Subject: Issue #146 - Part 2: Remove custom table painting component. Since we're now putting table borders and backgrounds properly in the display lists, we no longer need this custom component to do this work for us. --- layout/base/nsDisplayItemTypesList.h | 3 - layout/tables/moz.build | 1 - layout/tables/nsTableCellFrame.cpp | 14 - layout/tables/nsTableCellFrame.h | 5 - layout/tables/nsTableFrame.cpp | 84 ---- layout/tables/nsTableFrame.h | 10 - layout/tables/nsTablePainter.cpp | 696 --------------------------------- layout/tables/nsTablePainter.h | 268 ------------- layout/tables/nsTableRowFrame.cpp | 39 -- layout/tables/nsTableRowFrame.h | 1 - layout/tables/nsTableRowGroupFrame.cpp | 40 -- layout/tables/nsTableRowGroupFrame.h | 1 - 12 files changed, 1162 deletions(-) delete mode 100644 layout/tables/nsTablePainter.cpp delete mode 100644 layout/tables/nsTablePainter.h (limited to 'layout') diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h index d24f6f38f..cf809817f 100644 --- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -56,9 +56,6 @@ DECLARE_DISPLAY_ITEM_TYPE(SVG_PATH_GEOMETRY) DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT) DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION) -DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_BACKGROUND) -DECLARE_DISPLAY_ITEM_TYPE(TABLE_ROW_GROUP_BACKGROUND) -DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_BACKGROUND) DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE) DECLARE_DISPLAY_ITEM_TYPE(TEXT) DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW) diff --git a/layout/tables/moz.build b/layout/tables/moz.build index b77776320..e28e21ee0 100644 --- a/layout/tables/moz.build +++ b/layout/tables/moz.build @@ -21,7 +21,6 @@ UNIFIED_SOURCES += [ 'nsTableColFrame.cpp', 'nsTableColGroupFrame.cpp', 'nsTableFrame.cpp', - 'nsTablePainter.cpp', 'nsTableRowFrame.cpp', 'nsTableRowGroupFrame.cpp', 'nsTableWrapperFrame.cpp', diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index bac8d387f..ec9458f76 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -12,7 +12,6 @@ #include "nsTableColFrame.h" #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" -#include "nsTablePainter.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" #include "nsPresContext.h" @@ -380,19 +379,6 @@ nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext, return nsCSSRendering::PaintBackground(params); } -// Called by nsTablePainter -DrawResult -nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, nsPoint aPt, - uint32_t aFlags) -{ - if (!StyleVisibility()->IsVisible()) { - return DrawResult::SUCCESS; - } - - return PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags); -} - nsresult nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame, nsDisplayListBuilder* aBuilder, diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index 240809850..5f87c5f6d 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -107,11 +107,6 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - DrawResult PaintCellBackground(nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, nsPoint aPt, - uint32_t aFlags); - - virtual nsresult ProcessBorders(nsTableFrame* aFrame, nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index b5cd3b487..06a05292f 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -23,7 +23,6 @@ #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsTableWrapperFrame.h" -#include "nsTablePainter.h" #include "BasicTableLayoutStrategy.h" #include "FixedTableLayoutStrategy.h" @@ -1167,36 +1166,6 @@ nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder, static_cast(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt); } -class nsDisplayTableBorderBackground : public nsDisplayTableItem { -public: - nsDisplayTableBorderBackground(nsDisplayListBuilder* aBuilder, - nsTableFrame* aFrame, - bool aDrawsBackground) : - nsDisplayTableItem(aBuilder, aFrame, aDrawsBackground) { - MOZ_COUNT_CTOR(nsDisplayTableBorderBackground); - } -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayTableBorderBackground() { - MOZ_COUNT_DTOR(nsDisplayTableBorderBackground); - } -#endif - - virtual void Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) override; - NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND) -}; - -void -nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) -{ - DrawResult result = static_cast(mFrame)-> - PaintTableBorderBackground(aBuilder, *aCtx, mVisibleRect, - ToReferenceFrame()); - - nsDisplayTableItemGeometry::UpdateDrawResult(this, result); -} - /* static */ void nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) @@ -1383,59 +1352,6 @@ nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const return GetOuterBCBorder(wm).GetPhysicalMargin(wm); } -// XXX We don't put the borders and backgrounds in tree order like we should. -// That requires some major surgery which we aren't going to do right now. -DrawResult -nsTableFrame::PaintTableBorderBackground(nsDisplayListBuilder* aBuilder, - nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsPoint aPt) -{ - nsPresContext* presContext = PresContext(); - - uint32_t bgFlags = aBuilder->GetBackgroundPaintFlags(); - PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages() - ? PaintBorderFlags::SYNC_DECODE_IMAGES - : PaintBorderFlags(); - - TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table, - presContext, aRenderingContext, - aDirtyRect, aPt, bgFlags); - nsMargin deflate = GetDeflationForBackground(presContext); - // If 'deflate' is (0,0,0,0) then we'll paint the table background - // in a separate display item, so don't do it here. - DrawResult result = - painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0)); - - if (StyleVisibility()->IsVisible()) { - if (!IsBorderCollapse()) { - Sides skipSides = GetSkipSides(); - nsRect rect(aPt, mRect.Size()); - - result &= - nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, - aDirtyRect, rect, mStyleContext, - borderFlags, skipSides); - } else { - DrawTarget* drawTarget = aRenderingContext.GetDrawTarget(); - - gfxPoint devPixelOffset = - nsLayoutUtils::PointToGfxPoint(aPt, - PresContext()->AppUnitsPerDevPixel()); - - // XXX we should probably get rid of this translation at some stage - // But that would mean modifying PaintBCBorders, ugh - AutoRestoreTransform autoRestoreTransform(drawTarget); - drawTarget->SetTransform( - drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); - - PaintBCBorders(*drawTarget, aDirtyRect - aPt); - } - } - - return result; -} - nsIFrame::LogicalSides nsTableFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const { diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index d4b6d88a7..a6b786402 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -271,16 +271,6 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - /** - * Paint the background of the table and its parts (column groups, - * columns, row groups, rows, and cells), and the table border, and all - * internal borders if border-collapse is on. - */ - DrawResult PaintTableBorderBackground(nsDisplayListBuilder* aBuilder, - nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nsPoint aPt); - /** Get the outer half (i.e., the part outside the height and width of * the table) of the largest segment (?) of border-collapsed border on * the table on each side, or 0 for non border-collapsed tables. diff --git a/layout/tables/nsTablePainter.cpp b/layout/tables/nsTablePainter.cpp deleted file mode 100644 index bfe2a7d42..000000000 --- a/layout/tables/nsTablePainter.cpp +++ /dev/null @@ -1,696 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsTableFrame.h" -#include "nsTableRowGroupFrame.h" -#include "nsTableRowFrame.h" -#include "nsTableColGroupFrame.h" -#include "nsTableColFrame.h" -#include "nsTableCellFrame.h" -#include "nsTablePainter.h" -#include "nsCSSRendering.h" -#include "nsDisplayList.h" -#include "mozilla/WritingModes.h" - -/* ~*~ Table Background Painting ~*~ - - Mozilla's Table Background painting follows CSS2.1:17.5.1 - That section does not, however, describe the effect of - borders on background image positioning. What we do is: - - - in separate borders, the borders are passed in so that - their width figures in image positioning, even for rows/cols, which - don't have visible borders. This is done to allow authors - to position row backgrounds by, for example, aligning the - top left corner with the top left padding corner of the - top left table cell in the row in cases where all cells - have consistent border widths. If we didn't honor these - invisible borders, there would be no way to align - backgrounds with the padding edges, and designs would be - lost underneath the border. - - - in collapsing borders, because the borders collapse, we - use the -continuous border- width to synthesize a border - style and pass that in instead of using the element's - assigned style directly. - - The continuous border on a given edge of an element is - the collapse of all borders guaranteed to be continuous - along that edge. Cell borders are ignored (because, for - example, setting a thick border on the leftmost cell - should not shift the row background over; this way a - striped background set on
will line up across rows - even if the cells are assigned arbitrary border widths. - - For example, the continuous border on the top edge of a - row group is the collapse of any row group, row, and - table borders involved. (The first row group's top would - be [table-top + row group top + first row top]. It's bottom - would be [row group bottom + last row bottom + next row - top + next row group top].) - The top edge of a column group likewise includes the - table top, row group top, and first row top borders. However, - it *also* includes its own top border, since that is guaranteed - to be continuous. It does not include column borders because - those are not guaranteed to be continuous: there may be two - columns with different borders in a single column group. - - An alternative would be to define the continuous border as - [table? + row group + row] for horizontal - [table? + col group + col] for vertical - This makes it easier to line up backgrounds across elements - despite varying border widths, but it does not give much - flexibility in aligning /to/ those border widths. -*/ - - -/* ~*~ TableBackgroundPainter ~*~ - - The TableBackgroundPainter is created and destroyed in one painting call. - Its principal function is PaintTable, which paints all table element - backgrounds. The initial code in that method sets up an array of column - data that caches the background styles and the border sizes for the - columns and colgroups in TableBackgroundData structs in mCols. Data for - BC borders are calculated and stashed in a synthesized border style struct - in the data struct since collapsed borders aren't the same width as style- - assigned borders. The data struct optimizes by only doing this if there's - an image background; otherwise we don't care. //XXX should also check background-origin - The class then loops through the row groups, rows, and cells. At the cell - level, it paints the backgrounds, one over the other, inside the cell rect. - - The exception to this pattern is when a table element creates a (pseudo) - stacking context. Elements with stacking contexts (e.g., 'opacity' applied) - are passed through, which means their data (and their - descendants' data) are not cached. The full loop is still executed, however, - so that underlying layers can get painted at the cell level. - - The TableBackgroundPainter is then destroyed. - - Elements with stacking contexts set up their own painter to finish the - painting process, since they were skipped. They call the appropriate - sub-part of the loop (e.g. PaintRow) which will paint the frame and - descendants. - - XXX views are going - */ - -using namespace mozilla; -using namespace mozilla::image; - -TableBackgroundPainter::TableBackgroundData::TableBackgroundData() - : mFrame(nullptr) - , mVisible(false) - , mUsesSynthBorder(false) -{ -} - -TableBackgroundPainter::TableBackgroundData::TableBackgroundData(nsIFrame* aFrame) - : mFrame(aFrame) - , mRect(aFrame->GetRect()) - , mVisible(mFrame->IsVisibleForPainting()) - , mUsesSynthBorder(false) -{ -} - -inline bool -TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder() const -{ - /* we only need accurate border data when positioning background images*/ - if (!mVisible) { - return false; - } - - const nsStyleImageLayers& layers = mFrame->StyleBackground()->mImage; - NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) { - if (!layers.mLayers[i].mImage.IsEmpty()) - return true; - } - return false; -} - -void -TableBackgroundPainter::TableBackgroundData::SetBCBorder(const nsMargin& aBorder) -{ - mUsesSynthBorder = true; - mSynthBorderWidths = aBorder; -} - -nsStyleBorder -TableBackgroundPainter::TableBackgroundData::StyleBorder(const nsStyleBorder& aZeroBorder) const -{ - MOZ_ASSERT(mVisible, "Don't call StyleBorder on an invisible TableBackgroundData"); - - if (mUsesSynthBorder) { - nsStyleBorder result = aZeroBorder; - NS_FOR_CSS_SIDES(side) { - result.SetBorderWidth(side, mSynthBorderWidths.Side(side)); - } - return result; - } - - MOZ_ASSERT(mFrame); - - return *mFrame->StyleBorder(); -} - -TableBackgroundPainter::TableBackgroundPainter(nsTableFrame* aTableFrame, - Origin aOrigin, - nsPresContext* aPresContext, - nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - const nsPoint& aRenderPt, - uint32_t aBGPaintFlags) - : mPresContext(aPresContext), - mRenderingContext(aRenderingContext), - mRenderPt(aRenderPt), - mDirtyRect(aDirtyRect), - mOrigin(aOrigin), - mZeroBorder(aPresContext), - mBGPaintFlags(aBGPaintFlags) -{ - MOZ_COUNT_CTOR(TableBackgroundPainter); - - NS_FOR_CSS_SIDES(side) { - mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID); - mZeroBorder.SetBorderWidth(side, 0); - } - - mIsBorderCollapse = aTableFrame->IsBorderCollapse(); -#ifdef DEBUG - mCompatMode = mPresContext->CompatibilityMode(); -#endif - mNumCols = aTableFrame->GetColCount(); -} - -TableBackgroundPainter::~TableBackgroundPainter() -{ - MOZ_COUNT_DTOR(TableBackgroundPainter); -} - -DrawResult -TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame, - nsTableRowGroupFrame* aFirstRowGroup, - nsTableRowGroupFrame* aLastRowGroup, - const nsMargin& aDeflate) -{ - MOZ_ASSERT(aTableFrame, "null frame"); - TableBackgroundData tableData(aTableFrame); - tableData.mRect.MoveTo(0,0); //using table's coords - tableData.mRect.Deflate(aDeflate); - WritingMode wm = aTableFrame->GetWritingMode(); - if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) { - if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) { - //only handle non-degenerate tables; we need a more robust BC model - //to make degenerate tables' borders reasonable to deal with - LogicalMargin border(wm); - LogicalMargin tempBorder(wm); - nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1); - if (colFrame) { - colFrame->GetContinuousBCBorderWidth(wm, tempBorder); - } - border.IEnd(wm) = tempBorder.IEnd(wm); - - aLastRowGroup->GetContinuousBCBorderWidth(wm, tempBorder); - border.BEnd(wm) = tempBorder.BEnd(wm); - - nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow(); - if (rowFrame) { - rowFrame->GetContinuousBCBorderWidth(wm, tempBorder); - border.BStart(wm) = tempBorder.BStart(wm); - } - - border.IStart(wm) = aTableFrame->GetContinuousIStartBCBorderWidth(); - - tableData.SetBCBorder(border.GetPhysicalMargin(wm)); - } - } - - DrawResult result = DrawResult::SUCCESS; - - if (tableData.IsVisible()) { - nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForAllLayers(*mPresContext, - mRenderingContext, - mDirtyRect, - tableData.mRect + mRenderPt, - tableData.mFrame, - mBGPaintFlags); - - result &= - nsCSSRendering::PaintBackgroundWithSC(params, - tableData.mFrame->StyleContext(), - tableData.StyleBorder(mZeroBorder)); - } - - return result; -} - -void -TableBackgroundPainter::TranslateContext(nscoord aDX, - nscoord aDY) -{ - mRenderPt += nsPoint(aDX, aDY); - for (auto& col : mCols) { - col.mCol.mRect.MoveBy(-aDX, -aDY); - } - for (auto& colGroup : mColGroups) { - colGroup.mRect.MoveBy(-aDX, -aDY); - } -} - -TableBackgroundPainter::ColData::ColData(nsIFrame* aFrame, TableBackgroundData& aColGroupBGData) - : mCol(aFrame) - , mColGroup(aColGroupBGData) -{ -} - -DrawResult -TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame, - const nsMargin& aDeflate, - bool aPaintTableBackground) -{ - NS_PRECONDITION(aTableFrame, "null table frame"); - - nsTableFrame::RowGroupArray rowGroups; - aTableFrame->OrderRowGroups(rowGroups); - WritingMode wm = aTableFrame->GetWritingMode(); - - DrawResult result = DrawResult::SUCCESS; - - if (rowGroups.Length() < 1) { //degenerate case - if (aPaintTableBackground) { - result &= PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0)); - } - /* No cells; nothing else to paint */ - return result; - } - - if (aPaintTableBackground) { - result &= - PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1], - aDeflate); - } - - /*Set up column background/border data*/ - if (mNumCols > 0) { - nsFrameList& colGroupList = aTableFrame->GetColGroups(); - NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup"); - - // Collect all col group frames first so that we know how many there are. - nsTArray colGroupFrames; - for (nsTableColGroupFrame* cgFrame = static_cast(colGroupList.FirstChild()); - cgFrame; cgFrame = static_cast(cgFrame->GetNextSibling())) { - - if (cgFrame->GetColCount() < 1) { - //No columns, no cells, so no need for data - continue; - } - colGroupFrames.AppendElement(cgFrame); - } - - // Ensure that mColGroups won't reallocate during the loop below, because - // we grab references to its contents and need those to stay valid until - // mColGroups is destroyed as part of TablePainter destruction. - mColGroups.SetCapacity(colGroupFrames.Length()); - - LogicalMargin border(wm); - /* BC iStart borders aren't stored on cols, but the previous column's - iEnd border is the next one's iStart border.*/ - //Start with table's iStart border. - nscoord lastIStartBorder = aTableFrame->GetContinuousIStartBCBorderWidth(); - - for (nsTableColGroupFrame* cgFrame : colGroupFrames) { - /*Create data struct for column group*/ - TableBackgroundData& cgData = *mColGroups.AppendElement(TableBackgroundData(cgFrame)); - if (mIsBorderCollapse && cgData.ShouldSetBCBorder()) { - border.IStart(wm) = lastIStartBorder; - cgFrame->GetContinuousBCBorderWidth(wm, border); - cgData.SetBCBorder(border.GetPhysicalMargin(wm)); - } - - /*Loop over columns in this colgroup*/ - for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col; - col = static_cast(col->GetNextSibling())) { - MOZ_ASSERT(size_t(col->GetColIndex()) == mCols.Length()); - // Store a reference to the colGroup in the ColData element. - ColData& colData = *mCols.AppendElement(ColData(col, cgData)); - //Bring column mRect into table's coord system - colData.mCol.mRect.MoveBy(cgData.mRect.x, cgData.mRect.y); - if (mIsBorderCollapse) { - border.IStart(wm) = lastIStartBorder; - lastIStartBorder = col->GetContinuousBCBorderWidth(wm, border); - if (colData.mCol.ShouldSetBCBorder()) { - colData.mCol.SetBCBorder(border.GetPhysicalMargin(wm)); - } - } - } - } - } - - for (uint32_t i = 0; i < rowGroups.Length(); i++) { - nsTableRowGroupFrame* rg = rowGroups[i]; - TableBackgroundData rowGroupBGData(rg); - // Need to compute the right rect via GetOffsetTo, since the row - // group may not be a child of the table. - rowGroupBGData.mRect.MoveTo(rg->GetOffsetTo(aTableFrame)); - - // We have to draw backgrounds not only within the overflow region of this - // row group, but also possibly (in the case of column / column group - // backgrounds) at its pre-relative-positioning location. - nsRect rgVisualOverflow = rg->GetVisualOverflowRectRelativeToSelf(); - nsRect rgOverflowRect = rgVisualOverflow + rg->GetPosition(); - nsRect rgNormalRect = rgVisualOverflow + rg->GetNormalPosition(); - - if (rgOverflowRect.Union(rgNormalRect).Intersects(mDirtyRect - mRenderPt)) { - result &= - PaintRowGroup(rg, rowGroupBGData, rg->IsPseudoStackingContextFromStyle()); - } - } - - return result; -} - -DrawResult -TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame) -{ - return PaintRowGroup(aFrame, TableBackgroundData(aFrame), false); -} - -DrawResult -TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, - TableBackgroundData aRowGroupBGData, - bool aPassThrough) -{ - MOZ_ASSERT(aFrame, "null frame"); - - nsTableRowFrame* firstRow = aFrame->GetFirstRow(); - WritingMode wm = aFrame->GetWritingMode(); - - /* Load row group data */ - if (aPassThrough) { - aRowGroupBGData.MakeInvisible(); - } else { - if (mIsBorderCollapse && aRowGroupBGData.ShouldSetBCBorder()) { - LogicalMargin border(wm); - if (firstRow) { - //pick up first row's bstart border (= rg bstart border) - firstRow->GetContinuousBCBorderWidth(wm, border); - /* (row group doesn't store its bstart border) */ - } - //overwrite sides+bottom borders with rg's own - aFrame->GetContinuousBCBorderWidth(wm, border); - aRowGroupBGData.SetBCBorder(border.GetPhysicalMargin(wm)); - } - aPassThrough = !aRowGroupBGData.IsVisible(); - } - - /* translate everything into row group coord system*/ - if (eOrigin_TableRowGroup != mOrigin) { - TranslateContext(aRowGroupBGData.mRect.x, aRowGroupBGData.mRect.y); - } - nsRect rgRect = aRowGroupBGData.mRect; - aRowGroupBGData.mRect.MoveTo(0, 0); - - /* Find the right row to start with */ - - // Note that mDirtyRect - mRenderPt is guaranteed to be in the row - // group's coordinate system here, so passing its .y to - // GetFirstRowContaining is ok. - nscoord overflowAbove; - nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &overflowAbove); - - // Sadly, it seems like there may be non-row frames in there... or something? - // There are certainly null-checks in GetFirstRow() and GetNextRow(). :( - while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) { - cursor = cursor->GetNextSibling(); - } - - // It's OK if cursor is null here. - nsTableRowFrame* row = static_cast(cursor); - if (!row) { - // No useful cursor; just start at the top. Don't bother to set up a - // cursor; if we've gotten this far then we've already built the display - // list for the rowgroup, so not having a cursor means that there's some - // good reason we don't have a cursor and we shouldn't create one here. - row = firstRow; - } - - DrawResult result = DrawResult::SUCCESS; - - /* Finally paint */ - for (; row; row = row->GetNextRow()) { - TableBackgroundData rowBackgroundData(row); - - // Be sure to consider our positions both pre- and post-relative - // positioning, since we potentially need to paint at both places. - nscoord rowY = std::min(rowBackgroundData.mRect.y, row->GetNormalPosition().y); - - // Intersect wouldn't handle rowspans. - if (cursor && - (mDirtyRect.YMost() - mRenderPt.y) <= (rowY - overflowAbove)) { - // All done; cells originating in later rows can't intersect mDirtyRect. - break; - } - - result &= - PaintRow(row, aRowGroupBGData, rowBackgroundData, - aPassThrough || row->IsPseudoStackingContextFromStyle()); - } - - /* translate back into table coord system */ - if (eOrigin_TableRowGroup != mOrigin) { - TranslateContext(-rgRect.x, -rgRect.y); - } - - return result; -} - -DrawResult -TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame) -{ - return PaintRow(aFrame, TableBackgroundData(), TableBackgroundData(aFrame), false); -} - -DrawResult -TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, - const TableBackgroundData& aRowGroupBGData, - TableBackgroundData aRowBGData, - bool aPassThrough) -{ - MOZ_ASSERT(aFrame, "null frame"); - - /* Load row data */ - WritingMode wm = aFrame->GetWritingMode(); - if (aPassThrough) { - aRowBGData.MakeInvisible(); - } else { - if (mIsBorderCollapse && aRowBGData.ShouldSetBCBorder()) { - LogicalMargin border(wm); - nsTableRowFrame* nextRow = aFrame->GetNextRow(); - if (nextRow) { //outer bStart after us is inner bEnd for us - border.BEnd(wm) = nextRow->GetOuterBStartContBCBorderWidth(); - } - else { //acquire rg's bEnd border - nsTableRowGroupFrame* rowGroup = static_cast(aFrame->GetParent()); - rowGroup->GetContinuousBCBorderWidth(wm, border); - } - //get the rest of the borders; will overwrite all but bEnd - aFrame->GetContinuousBCBorderWidth(wm, border); - - aRowBGData.SetBCBorder(border.GetPhysicalMargin(wm)); - } - aPassThrough = !aRowBGData.IsVisible(); - } - - /* Translate */ - if (eOrigin_TableRow == mOrigin) { - /* If we originate from the row, then make the row the origin. */ - aRowBGData.mRect.MoveTo(0, 0); - } - //else: Use row group's coord system -> no translation necessary - - DrawResult result = DrawResult::SUCCESS; - - for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) { - nsRect cellBGRect, rowBGRect, rowGroupBGRect, colBGRect; - ComputeCellBackgrounds(cell, aRowGroupBGData, aRowBGData, - cellBGRect, rowBGRect, - rowGroupBGRect, colBGRect); - - // Find the union of all the cell background layers. - nsRect combinedRect(cellBGRect); - combinedRect.UnionRect(combinedRect, rowBGRect); - combinedRect.UnionRect(combinedRect, rowGroupBGRect); - combinedRect.UnionRect(combinedRect, colBGRect); - - if (combinedRect.Intersects(mDirtyRect)) { - bool passCell = aPassThrough || cell->IsPseudoStackingContextFromStyle(); - result &= - PaintCell(cell, aRowGroupBGData, aRowBGData, cellBGRect, rowBGRect, - rowGroupBGRect, colBGRect, passCell); - } - } - - return result; -} - -DrawResult -TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, - const TableBackgroundData& aRowGroupBGData, - const TableBackgroundData& aRowBGData, - nsRect& aCellBGRect, - nsRect& aRowBGRect, - nsRect& aRowGroupBGRect, - nsRect& aColBGRect, - bool aPassSelf) -{ - MOZ_ASSERT(aCell, "null frame"); - - const nsStyleTableBorder* cellTableStyle; - cellTableStyle = aCell->StyleTableBorder(); - if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW != cellTableStyle->mEmptyCells && - aCell->GetContentEmpty() && !mIsBorderCollapse) { - return DrawResult::SUCCESS; - } - - int32_t colIndex; - aCell->GetColIndex(colIndex); - // We're checking mNumCols instead of mCols.Length() here because mCols can - // be empty even if mNumCols > 0. - NS_ASSERTION(size_t(colIndex) < mNumCols, "out-of-bounds column index"); - if (size_t(colIndex) >= mNumCols) { - return DrawResult::SUCCESS; - } - - // If callers call PaintRowGroup or PaintRow directly, we haven't processed - // our columns. Ignore column / col group backgrounds in that case. - bool haveColumns = !mCols.IsEmpty(); - - DrawResult result = DrawResult::SUCCESS; - - //Paint column group background - if (haveColumns && mCols[colIndex].mColGroup.IsVisible()) { - nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForAllLayers(*mPresContext, mRenderingContext, - mDirtyRect, - mCols[colIndex].mColGroup.mRect + mRenderPt, - mCols[colIndex].mColGroup.mFrame, - mBGPaintFlags); - params.bgClipRect = &aColBGRect; - result &= - nsCSSRendering::PaintBackgroundWithSC(params, - mCols[colIndex].mColGroup.mFrame->StyleContext(), - mCols[colIndex].mColGroup.StyleBorder(mZeroBorder)); - } - - //Paint column background - if (haveColumns && mCols[colIndex].mCol.IsVisible()) { - nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForAllLayers(*mPresContext, mRenderingContext, - mDirtyRect, - mCols[colIndex].mCol.mRect + mRenderPt, - mCols[colIndex].mCol.mFrame, - mBGPaintFlags); - params.bgClipRect = &aColBGRect; - result &= - nsCSSRendering::PaintBackgroundWithSC(params, - mCols[colIndex].mCol.mFrame->StyleContext(), - mCols[colIndex].mCol.StyleBorder(mZeroBorder)); - } - - //Paint row group background - if (aRowGroupBGData.IsVisible()) { - nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForAllLayers(*mPresContext, mRenderingContext, - mDirtyRect, - aRowGroupBGData.mRect + mRenderPt, - aRowGroupBGData.mFrame, mBGPaintFlags); - params.bgClipRect = &aRowGroupBGRect; - result &= - nsCSSRendering::PaintBackgroundWithSC(params, - aRowGroupBGData.mFrame->StyleContext(), - aRowGroupBGData.StyleBorder(mZeroBorder)); - } - - //Paint row background - if (aRowBGData.IsVisible()) { - nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForAllLayers(*mPresContext, mRenderingContext, - mDirtyRect, - aRowBGData.mRect + mRenderPt, - aRowBGData.mFrame, mBGPaintFlags); - params.bgClipRect = &aRowBGRect; - result &= - nsCSSRendering::PaintBackgroundWithSC(params, - aRowBGData.mFrame->StyleContext(), - aRowBGData.StyleBorder(mZeroBorder)); - } - - //Paint cell background in border-collapse unless we're just passing - if (mIsBorderCollapse && !aPassSelf) { - result &= - aCell->PaintCellBackground(mRenderingContext, mDirtyRect, - aCellBGRect.TopLeft(), mBGPaintFlags); - } - - return result; -} - -void -TableBackgroundPainter::ComputeCellBackgrounds(nsTableCellFrame* aCell, - const TableBackgroundData& aRowGroupBGData, - const TableBackgroundData& aRowBGData, - nsRect& aCellBGRect, - nsRect& aRowBGRect, - nsRect& aRowGroupBGRect, - nsRect& aColBGRect) -{ - // We need to compute table background layer rects for this cell space, - // adjusted for possible relative positioning. This behavior is not specified - // at the time of this writing, but the approach below should be web - // compatible. - // - // Our goal is that relative positioning of a table part should leave - // backgrounds *under* that part unchanged. ("Under" being defined by CSS 2.1 - // Section 17.5.1.) If a cell is positioned, we do not expect the row - // background to move. On the other hand, the backgrounds of layers *above* - // the positioned part are taken along for the ride -- for example, - // positioning a row group will also cause the row background to be drawn in - // the new location, unless it has further positioning applied. - // - // Each table part layer has its position stored in the coordinate space of - // the layer below (which is to say, its geometric parent), and the stored - // position is the post-relative-positioning one. The position of each - // background layer rect is thus determined by peeling off successive table - // part layers, removing the contribution of each layer's positioning one by - // one. Every rect we generate will be the same size, the size of the cell - // space. - - // We cannot rely on the row group background data to be available, since some - // callers enter through PaintRow. - nsIFrame* rowGroupFrame = - aRowGroupBGData.mFrame ? aRowGroupBGData.mFrame : aRowBGData.mFrame->GetParent(); - - // The cell background goes at the cell's position, translated to use the same - // coordinate system as aRowBGData. - aCellBGRect = aCell->GetRect() + aRowBGData.mRect.TopLeft() + mRenderPt; - - // The row background goes at the normal position of the cell, which is to say - // the position without relative positioning applied. - aRowBGRect = aCellBGRect + (aCell->GetNormalPosition() - aCell->GetPosition()); - - // The row group background goes at the position we'd find the cell if neither - // the cell's relative positioning nor the row's were applied. - aRowGroupBGRect = aRowBGRect + - (aRowBGData.mFrame->GetNormalPosition() - aRowBGData.mFrame->GetPosition()); - - // The column and column group backgrounds (they're always at the same - // location, since relative positioning doesn't apply to columns or column - // groups) are drawn at the position we'd find the cell if none of the cell's, - // row's, or row group's relative positioning were applied. - aColBGRect = aRowGroupBGRect + - (rowGroupFrame->GetNormalPosition() - rowGroupFrame->GetPosition()); - -} diff --git a/layout/tables/nsTablePainter.h b/layout/tables/nsTablePainter.h deleted file mode 100644 index dfba42156..000000000 --- a/layout/tables/nsTablePainter.h +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsTablePainter_h__ -#define nsTablePainter_h__ - -#include "imgIContainer.h" - -#include "celldata.h" - -// flags for Paint, PaintChild, PaintChildren are currently only used by tables. -//Table-based paint call; not a direct call as with views -#define NS_PAINT_FLAG_TABLE_BG_PAINT 0x00000001 -//Cells should paint their backgrounds only, no children -#define NS_PAINT_FLAG_TABLE_CELL_BG_PASS 0x00000002 - -class nsIFrame; -class nsTableFrame; -class nsTableRowGroupFrame; -class nsTableRowFrame; -class nsTableCellFrame; - -class TableBackgroundPainter -{ - /* - * Helper class for painting table backgrounds - * - */ - - typedef mozilla::image::DrawResult DrawResult; - - public: - - enum Origin { eOrigin_Table, eOrigin_TableRowGroup, eOrigin_TableRow }; - - /** Public constructor - * @param aTableFrame - the table's table frame - * @param aOrigin - what type of table frame is creating this instance - * @param aPresContext - the presentation context - * @param aRenderingContext - the rendering context - * @param aDirtyRect - the area that needs to be painted, - * relative to aRenderingContext - * @param aPt - offset of the table frame relative to - * aRenderingContext - * @param aBGPaintFlags - Flags of the nsCSSRendering::PAINTBG_* variety - */ - TableBackgroundPainter(nsTableFrame* aTableFrame, - Origin aOrigin, - nsPresContext* aPresContext, - nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - const nsPoint& aPt, - uint32_t aBGPaintFlags); - - /** Destructor */ - ~TableBackgroundPainter(); - - /* ~*~ The Border Collapse Painting Issue ~*~ - - In border-collapse, the *table* paints the cells' borders, - so we need to make sure the backgrounds get painted first - (underneath) by doing a cell-background-only painting pass. - */ - - /* ~*~ Using nsTablePainter Background Painting ~*~ - - A call to PaintTable will normally paint all of the table's - elements (except for the table background, if aPaintTableBackground - is false). - Elements with views however, will be skipped and must create their - own painter to call the appropriate paint function in their ::Paint - method (e.g. painter.PaintRow in nsTableRow::Paint) - */ - - /** Paint background for the table frame (if requested) and its children - * down through cells. - * (Cells themselves will only be painted in border collapse) - * Table must do a flagged TABLE_BG_PAINT ::Paint call on its - * children afterwards - * @param aTableFrame - the table frame - * @param aDeflate - deflation needed to bring table's mRect - * to the outer grid lines in border-collapse - * @param aPaintTableBackground - if true, the table background - * is included, otherwise it isn't - * @returns DrawResult::SUCCESS if all painting was successful. If some - * painting failed or an improved result could be achieved by sync - * decoding images, returns another value. - */ - DrawResult PaintTable(nsTableFrame* aTableFrame, const nsMargin& aDeflate, - bool aPaintTableBackground); - - /** Paint background for the row group and its children down through cells - * (Cells themselves will only be painted in border collapse) - * Standards mode only - * Table Row Group must do a flagged TABLE_BG_PAINT ::Paint call on its - * children afterwards - * @param aFrame - the table row group frame - * @returns DrawResult::SUCCESS if all painting was successful. If some - * painting failed or an improved result could be achieved by sync - * decoding images, returns another value. - */ - DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame); - - /** Paint background for the row and its children down through cells - * (Cells themselves will only be painted in border collapse) - * Standards mode only - * Table Row must do a flagged TABLE_BG_PAINT ::Paint call on its - * children afterwards - * @param aFrame - the table row frame - * @returns DrawResult::SUCCESS if all painting was successful. If some - * painting failed or an improved result could be achieved by sync - * decoding images, returns another value. - */ - DrawResult PaintRow(nsTableRowFrame* aFrame); - - private: - struct TableBackgroundData; - - /** Paint table frame's background - * @param aTableFrame - the table frame - * @param aFirstRowGroup - the first (in layout order) row group - * may be null - * @param aLastRowGroup - the last (in layout order) row group - * may be null - * @param aDeflate - adjustment to frame's rect (used for quirks BC) - * may be null - */ - DrawResult PaintTableFrame(nsTableFrame* aTableFrame, - nsTableRowGroupFrame* aFirstRowGroup, - nsTableRowGroupFrame* aLastRowGroup, - const nsMargin& aDeflate); - - /* aPassThrough params indicate whether to paint the element or to just - * pass through and paint underlying layers only. - * aRowGroupBGData is not a const reference because the function modifies - * its copy. Same for aRowBGData in PaintRow. - * See Public versions for function descriptions - */ - DrawResult PaintRowGroup(nsTableRowGroupFrame* aFrame, - TableBackgroundData aRowGroupBGData, - bool aPassThrough); - - DrawResult PaintRow(nsTableRowFrame* aFrame, - const TableBackgroundData& aRowGroupBGData, - TableBackgroundData aRowBGData, - bool aPassThrough); - - /** Paint table background layers for this cell space - * Also paints cell's own background in border-collapse mode - * @param aCell - the cell - * @param aRowGroupBGData - background drawing info for the row group - * @param aRowBGData - background drawing info for the row - * @param aCellBGRect - background rect for the cell - * @param aRowBGRect - background rect for the row - * @param aRowGroupBGRect - background rect for the row group - * @param aColBGRect - background rect for the column and column group - * @param aPassSelf - pass this cell; i.e. paint only underlying layers - */ - DrawResult PaintCell(nsTableCellFrame* aCell, - const TableBackgroundData& aRowGroupBGData, - const TableBackgroundData& aRowBGData, - nsRect& aCellBGRect, - nsRect& aRowBGRect, - nsRect& aRowGroupBGRect, - nsRect& aColBGRect, - bool aPassSelf); - - /** Compute table background layer positions for this cell space - * @param aCell - the cell - * @param aRowGroupBGData - background drawing info for the row group - * @param aRowBGData - background drawing info for the row - * @param aCellBGRectOut - outparam: background rect for the cell - * @param aRowBGRectOut - outparam: background rect for the row - * @param aRowGroupBGRectOut - outparam: background rect for the row group - * @param aColBGRectOut - outparam: background rect for the column - and column group - */ - void ComputeCellBackgrounds(nsTableCellFrame* aCell, - const TableBackgroundData& aRowGroupBGData, - const TableBackgroundData& aRowBGData, - nsRect& aCellBGRect, - nsRect& aRowBGRect, - nsRect& aRowGroupBGRect, - nsRect& aColBGRect); - - /** Translate mRenderingContext, mDirtyRect, and mCols' column and - * colgroup coords - * @param aDX - origin's x-coord change - * @param aDY - origin's y-coord change - */ - void TranslateContext(nscoord aDX, - nscoord aDY); - - struct TableBackgroundData { - public: - /** - * Construct an empty TableBackgroundData instance, which is invisible. - */ - TableBackgroundData(); - - /** - * Construct a TableBackgroundData instance for a frame. Visibility will - * be derived from the frame and can be overridden using MakeInvisible(). - */ - explicit TableBackgroundData(nsIFrame* aFrame); - - /** Destructor */ - ~TableBackgroundData() {} - - /** Data is valid & frame is visible */ - bool IsVisible() const { return mVisible; } - - /** Override visibility of the frame, force it to be invisible */ - void MakeInvisible() { mVisible = false; } - - /** True if need to set border-collapse border; must call SetFull beforehand */ - bool ShouldSetBCBorder() const; - - /** Set border-collapse border with aBorderWidth as widths */ - void SetBCBorder(const nsMargin& aBorderWidth); - - /** - * @param aZeroBorder An nsStyleBorder instance that has been initialized - * for the right nsPresContext, with all border widths - * set to zero and border styles set to solid. - * @return The nsStyleBorder that should be used for rendering - * this background. - */ - nsStyleBorder StyleBorder(const nsStyleBorder& aZeroBorder) const; - - nsIFrame* const mFrame; - - /** mRect is the rect of mFrame in the current coordinate system */ - nsRect mRect; - - private: - nsMargin mSynthBorderWidths; - bool mVisible; - bool mUsesSynthBorder; - }; - - struct ColData { - ColData(nsIFrame* aFrame, TableBackgroundData& aColGroupBGData); - TableBackgroundData mCol; - TableBackgroundData& mColGroup; // reference to col's parent colgroup's data, owned by TablePainter in mColGroups - }; - - nsPresContext* mPresContext; - nsRenderingContext& mRenderingContext; - nsPoint mRenderPt; - nsRect mDirtyRect; -#ifdef DEBUG - nsCompatibility mCompatMode; -#endif - bool mIsBorderCollapse; - Origin mOrigin; //user's table frame type - - nsTArray mColGroups; - nsTArray mCols; - size_t mNumCols; - - nsStyleBorder mZeroBorder; //cached zero-width border - uint32_t mBGPaintFlags; -}; - -#endif diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index dc053c991..05b9deee9 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -561,45 +561,6 @@ nsTableRowFrame::CalcBSize(const ReflowInput& aReflowInput) return GetInitialBSize(); } -/** - * We need a custom display item for table row backgrounds. This is only used - * when the table row is the root of a stacking context (e.g., has 'opacity'). - * Table row backgrounds can extend beyond the row frame bounds, when - * the row contains row-spanning cells. - */ -class nsDisplayTableRowBackground : public nsDisplayTableItem { -public: - nsDisplayTableRowBackground(nsDisplayListBuilder* aBuilder, - nsTableRowFrame* aFrame) : - nsDisplayTableItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayTableRowBackground); - } -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayTableRowBackground() { - MOZ_COUNT_DTOR(nsDisplayTableRowBackground); - } -#endif - - virtual void Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) override; - NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND) -}; - -void -nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) -{ - auto rowFrame = static_cast(mFrame); - TableBackgroundPainter painter(rowFrame->GetTableFrame(), - TableBackgroundPainter::eOrigin_TableRow, - mFrame->PresContext(), *aCtx, - mVisibleRect, ToReferenceFrame(), - aBuilder->GetBackgroundPaintFlags()); - - DrawResult result = painter.PaintRow(rowFrame); - nsDisplayTableItemGeometry::UpdateDrawResult(this, result); -} - void nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index a6aba81e7..9e15d851f 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -8,7 +8,6 @@ #include "mozilla/Attributes.h" #include "nscore.h" #include "nsContainerFrame.h" -#include "nsTablePainter.h" #include "nsTableRowGroupFrame.h" #include "mozilla/WritingModes.h" diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 943bdf50b..3e4f60f62 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -154,46 +154,6 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame return NS_OK; } -/** - * We need a custom display item for table row backgrounds. This is only used - * when the table row is the root of a stacking context (e.g., has 'opacity'). - * Table row backgrounds can extend beyond the row frame bounds, when - * the row contains row-spanning cells. - */ -class nsDisplayTableRowGroupBackground : public nsDisplayTableItem { -public: - nsDisplayTableRowGroupBackground(nsDisplayListBuilder* aBuilder, - nsTableRowGroupFrame* aFrame) : - nsDisplayTableItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground); - } -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayTableRowGroupBackground() { - MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground); - } -#endif - - virtual void Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) override; - - NS_DISPLAY_DECL_NAME("TableRowGroupBackground", TYPE_TABLE_ROW_GROUP_BACKGROUND) -}; - -void -nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) -{ - auto rgFrame = static_cast(mFrame); - TableBackgroundPainter painter(rgFrame->GetTableFrame(), - TableBackgroundPainter::eOrigin_TableRowGroup, - mFrame->PresContext(), *aCtx, - mVisibleRect, ToReferenceFrame(), - aBuilder->GetBackgroundPaintFlags()); - - DrawResult result = painter.PaintRowGroup(rgFrame); - nsDisplayTableItemGeometry::UpdateDrawResult(this, result); -} - // Handle the child-traversal part of DisplayGenericTablePart static void DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index 7abdd4b74..721d91046 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -10,7 +10,6 @@ #include "nsContainerFrame.h" #include "nsIAtom.h" #include "nsILineIterator.h" -#include "nsTablePainter.h" #include "nsTArray.h" #include "nsTableFrame.h" #include "mozilla/WritingModes.h" -- cgit v1.2.3 From db98e3efff6087b690805358e6f4fda118ec9627 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 15:12:34 +0100 Subject: Issue #146 - Part 3: Create nsDisplayTableFixedPosition to avoid display list collisions when processing the background image of a table. --- layout/base/nsDisplayList.cpp | 63 ++++++++++++++++++++++++++++++++++++++++-- layout/base/nsDisplayList.h | 45 ++++++++++++++++++++++++++++-- layout/tables/nsTableFrame.cpp | 8 ++++-- 3 files changed, 108 insertions(+), 8 deletions(-) (limited to 'layout') diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 744153831..6b792a779 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -80,6 +80,8 @@ #include "nsPluginFrame.h" #include "DisplayItemScrollClip.h" #include "nsSVGMaskFrame.h" +#include "nsTableCellFrame.h" +#include "nsTableColFrame.h" // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to // GetTickCount(). @@ -2632,7 +2634,8 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil nsDisplayList* aList, bool aAllowWillPaintBorderOptimization, nsStyleContext* aStyleContext, - const nsRect& aBackgroundOriginRect) + const nsRect& aBackgroundOriginRect, + nsIFrame* aSecondaryReferenceFrame) { nsStyleContext* bgSC = aStyleContext; const nsStyleBackground* bg = nullptr; @@ -2752,8 +2755,17 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgOriginRect, bg); if (bgItem->ShouldFixToViewport(aBuilder)) { - thisItemList.AppendNewToTop( - nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i)); + if (aSecondaryReferenceFrame) { + thisItemList.AppendNewToTop( + nsDisplayTableFixedPosition::CreateForFixedBackground(aBuilder, + aSecondaryReferenceFrame, + bgItem, + i, + aFrame)); + } else { + thisItemList.AppendNewToTop( + nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i)); + } } else { thisItemList.AppendNewToTop(bgItem); } @@ -5277,6 +5289,51 @@ bool nsDisplayFixedPosition::TryMerge(nsDisplayItem* aItem) { return true; } +TableType +GetTableTypeFromFrame(nsIFrame* aFrame) +{ + nsIAtom* type = aFrame->GetType(); + if (type == nsGkAtoms::tableFrame) { + return TableType::TABLE; + } else if (type == nsGkAtoms::tableColFrame) { + return TableType::TABLE_COL; + } else if (type == nsGkAtoms::tableColGroupFrame) { + return TableType::TABLE_COL_GROUP; + } else if (type == nsGkAtoms::tableRowFrame) { + return TableType::TABLE_ROW; + } else if (type == nsGkAtoms::tableRowGroupFrame) { + return TableType::TABLE_ROW_GROUP; + } else if (type == nsGkAtoms::tableCellFrame) { + return TableType::TABLE_CELL; + } else { + MOZ_ASSERT_UNREACHABLE("Invalid frame."); + return TableType::TABLE; + } +} + +nsDisplayTableFixedPosition::nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + nsDisplayList* aList, + uint32_t aIndex, + nsIFrame* aAncestorFrame) + : nsDisplayFixedPosition(aBuilder, aFrame, aList, aIndex) + , mTableType(GetTableTypeFromFrame(aAncestorFrame)) +{ +} + +/* static */ nsDisplayTableFixedPosition* +nsDisplayTableFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + nsDisplayBackgroundImage* aImage, + uint32_t aIndex, + nsIFrame* aAncestorFrame) +{ + nsDisplayList temp; + temp.AppendToTop(aImage); + + return new (aBuilder) nsDisplayTableFixedPosition(aBuilder, aFrame, &temp, aIndex + 1, aAncestorFrame); +} + nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 9431e2cc0..69d13ded9 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2738,7 +2738,8 @@ public: nsDisplayList* aList, bool aAllowWillPaintBorderOptimization = true, nsStyleContext* aStyleContext = nullptr, - const nsRect& aBackgroundOriginRect = nsRect()); + const nsRect& aBackgroundOriginRect = nsRect(), + nsIFrame* aSecondaryReferenceFrame = nullptr); virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, @@ -2838,6 +2839,25 @@ protected: bool mShouldTreatAsFixed; }; +enum class TableType : uint8_t { + TABLE, + TABLE_COL, + TABLE_COL_GROUP, + TABLE_ROW, + TABLE_ROW_GROUP, + TABLE_CELL, + + TABLE_TYPE_MAX +}; + +enum class TableTypeBits : uint8_t { + COUNT = 3 +}; + +static_assert( + static_cast(TableType::TABLE_TYPE_MAX) < (1 << (static_cast(TableTypeBits::COUNT) + 1)), + "TableType cannot fit with TableTypeBits::COUNT"); +TableType GetTableTypeFromFrame(nsIFrame* aFrame); /** * A display item to paint the native theme background for a frame. @@ -3736,7 +3756,7 @@ public: return mAnimatedGeometryRootForScrollMetadata; } -private: +protected: // For background-attachment:fixed nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, uint32_t aIndex); @@ -3747,6 +3767,27 @@ private: bool mIsFixedBackground; }; +class nsDisplayTableFixedPosition : public nsDisplayFixedPosition +{ +public: + static nsDisplayTableFixedPosition* CreateForFixedBackground(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + nsDisplayBackgroundImage* aImage, + uint32_t aIndex, + nsIFrame* aAncestorFrame); + + virtual uint32_t GetPerFrameKey() override { + return (mIndex << (nsDisplayItem::TYPE_BITS + static_cast(TableTypeBits::COUNT))) | + (static_cast(mTableType) << nsDisplayItem::TYPE_BITS) | + nsDisplayItem::GetPerFrameKey(); + } +protected: + nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint32_t aIndex, nsIFrame* aAncestorFrame); + + TableType mTableType; +}; + /** * This creates an empty scrollable layer. It has no child layers. * It is used to record the existence of a scrollable frame in the layer diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 06a05292f..890d050fd 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1194,13 +1194,14 @@ PaintRowBackground(nsTableRowFrame* aRow, const nsDisplayListSet& aLists, const nsPoint& aOffset = nsPoint()) { - // Compute background rect by iterating all cell frame. + // Compute background rect by iterating over all cell frames. for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, aLists.BorderBackground(), true, nullptr, - aFrame->GetRectRelativeToSelf()); + aFrame->GetRectRelativeToSelf(), + cell); } } @@ -1232,7 +1233,8 @@ PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, aLists.BorderBackground(), true, nullptr, - aFrame->GetRectRelativeToSelf()); + aFrame->GetRectRelativeToSelf(), + cell); } } } -- cgit v1.2.3 From ee663e2930650d181be1f7792952dfc32baf0bf0 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 17:25:37 +0100 Subject: Issue #146 - Part 3: Create nsDisplayTableBackgroundImage to avoid display list collisions when processing the background image of a table. --- layout/base/nsDisplayList.cpp | 45 ++++++++++++++++++++++++++++++++++++------- layout/base/nsDisplayList.h | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 7 deletions(-) (limited to 'layout') diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 6b792a779..1579e6970 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2751,9 +2751,19 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil } nsDisplayList thisItemList; - nsDisplayBackgroundImage* bgItem = - new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgOriginRect, bg); - + nsDisplayBackgroundImage* bgItem; + if (aSecondaryReferenceFrame) { + bgItem = + new (aBuilder) nsDisplayTableBackgroundImage(aBuilder, + aFrame, + i, + bgOriginRect, + bg, + aSecondaryReferenceFrame); + } else { + bgItem = + new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgOriginRect, bg); + } if (bgItem->ShouldFixToViewport(aBuilder)) { if (aSecondaryReferenceFrame) { thisItemList.AppendNewToTop( @@ -2906,7 +2916,7 @@ nsDisplayBackgroundImage::ImageLayerization nsDisplayBackgroundImage::ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager) { - nsIFrame* backgroundStyleFrame = nsCSSRendering::FindBackgroundStyleFrame(mFrame); + nsIFrame* backgroundStyleFrame = nsCSSRendering::FindBackgroundStyleFrame(StyleFrame()); if (ActiveLayerTracker::IsBackgroundPositionAnimated(aBuilder, backgroundStyleFrame)) { return WHENEVER_POSSIBLE; @@ -3161,16 +3171,16 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder, StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip; if (clip == StyleGeometryBox::Text) { - if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) { + if (!GenerateAndPushTextMask(StyleFrame(), aCtx, mBackgroundRect, aBuilder)) { return; } } nsCSSRendering::PaintBGParams params = - nsCSSRendering::PaintBGParams::ForSingleLayer(*mFrame->PresContext(), + nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(), *aCtx, aBounds, mBackgroundRect, - mFrame, flags, mLayer, + StyleFrame(), flags, mLayer, CompositionOp::OP_OVER); params.bgClipRect = aClipRect; image::DrawResult result = @@ -3272,6 +3282,27 @@ nsDisplayBackgroundImage::GetPerFrameKey() nsDisplayItem::GetPerFrameKey(); } +nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + uint32_t aLayer, + const nsRect& aBackgroundRect, + const nsStyleBackground* aBackgroundStyle, + nsIFrame* aCellFrame) + : nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aBackgroundRect, aBackgroundStyle) + , mStyleFrame(aFrame) + , mTableType(GetTableTypeFromFrame(mStyleFrame)) +{ + mFrame = aCellFrame; +} + +bool +nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect) +{ + bool result = mStyleFrame ? mStyleFrame->IsInvalid(aRect) : false; + aRect += ToReferenceFrame(); + return result; +} + nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const nsRect& aBackgroundRect) diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 69d13ded9..e9047b113 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2814,6 +2814,8 @@ protected: void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, const nsRect& aBounds, nsRect* aClipRect); + virtual nsIFrame* StyleFrame() { return mFrame; } + // Determine whether we want to be separated into our own layer, independent // of whether this item can actually be layerized. enum ImageLayerization { @@ -2859,6 +2861,41 @@ static_assert( "TableType cannot fit with TableTypeBits::COUNT"); TableType GetTableTypeFromFrame(nsIFrame* aFrame); +/** + * A display item to paint background image for table. For table parts, such + * as row, row group, col, col group, when drawing its background, we'll + * create separate background image display item for its containning cell. + * Those background image display items will reference to same DisplayItemData + * if we keep the mFrame point to cell's ancestor frame. We don't want to this + * happened bacause share same DisplatItemData will cause many bugs. So that + * we let mFrame point to cell frame and store the table type of the ancestor + * frame. And use mFrame and table type as key to generate DisplayItemData to + * avoid sharing DisplayItemData. + * + * Also store ancestor frame as mStyleFrame for all rendering informations. + */ +class nsDisplayTableBackgroundImage : public nsDisplayBackgroundImage { +public: + nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + uint32_t aLayer, + const nsRect& aBackgroundRect, + const nsStyleBackground* aBackgroundStyle, + nsIFrame* aCellFrame); + + virtual uint32_t GetPerFrameKey() override { + return (static_cast(mTableType) << nsDisplayItem::TYPE_BITS) | + nsDisplayItem::GetPerFrameKey(); + } + + virtual bool IsInvalid(nsRect& aRect) override; +protected: + virtual nsIFrame* StyleFrame() override { return mStyleFrame; } + + nsIFrame* mStyleFrame; + TableType mTableType; +}; + /** * A display item to paint the native theme background for a frame. */ -- cgit v1.2.3 From f1b043af1dd09b2a5235ee88be9a5b547697fa5b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 18:49:57 +0100 Subject: Issue #146 - Part 4: Adjust tests for fixes. This also adds a reftest for border radius on collapsed borders (should be ignored according to the CSS3 standard). We didn't do this before, except on internal elements. --- layout/reftests/table-background/reftest.list | 6 +++--- .../table-bordercollapse/bc_borderradius-ref.html | 17 +++++++++++++++++ .../reftests/table-bordercollapse/bc_borderradius.html | 18 ++++++++++++++++++ layout/reftests/table-bordercollapse/reftest.list | 4 +++- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 layout/reftests/table-bordercollapse/bc_borderradius-ref.html create mode 100644 layout/reftests/table-bordercollapse/bc_borderradius.html (limited to 'layout') diff --git a/layout/reftests/table-background/reftest.list b/layout/reftests/table-background/reftest.list index eb2817ca0..68dc43e95 100644 --- a/layout/reftests/table-background/reftest.list +++ b/layout/reftests/table-background/reftest.list @@ -44,11 +44,11 @@ fuzzy-if(d2d,1,1083) fuzzy-if(skiaContent,1,2200) == border-collapse-opacity-tab fails == border-collapse-opacity-table-column-group.html border-collapse-opacity-table-column-group-ref.html # bug 424274 fails == border-collapse-opacity-table-column.html border-collapse-opacity-table-column-ref.html # bug 424274 fuzzy-if(d2d,1,16359) fuzzy-if(skiaContent,1,17000) == border-collapse-opacity-table-row-group.html border-collapse-opacity-table-row-group-ref.html -fuzzy-if(d2d,1,5453) fuzzy-if(skiaContent,1,11000) == border-collapse-opacity-table-row.html border-collapse-opacity-table-row-ref.html +fuzzy-if(d2d,1,11000) fuzzy-if(skiaContent,1,11000) == border-collapse-opacity-table-row.html border-collapse-opacity-table-row-ref.html fuzzy-if(d2d||skiaContent,1,60000) == border-collapse-opacity-table.html border-collapse-opacity-table-ref.html fuzzy-if(d2d,1,2478) fuzzy-if(skiaContent,1,2500) == border-separate-opacity-table-cell.html border-separate-opacity-table-cell-ref.html -fails == border-separate-opacity-table-column-group.html border-separate-opacity-table-column-group-ref.html # bug 424274 -fails == border-separate-opacity-table-column.html border-separate-opacity-table-column-ref.html # bug 424274 +fuzzy-if(d2d,1,38000) == border-separate-opacity-table-column-group.html border-separate-opacity-table-column-group-ref.html # bug 424274 +fuzzy-if(d2d,1,13000) == border-separate-opacity-table-column.html border-separate-opacity-table-column-ref.html # bug 424274 fuzzy-if(d2d,1,37170) fuzzy-if(skiaContent,1,38000) == border-separate-opacity-table-row-group.html border-separate-opacity-table-row-group-ref.html fuzzy-if(d2d,1,12390) fuzzy-if(skiaContent,1,13000) == border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html fuzzy-if(d2d||skiaContent,1,95000) == border-separate-opacity-table.html border-separate-opacity-table-ref.html diff --git a/layout/reftests/table-bordercollapse/bc_borderradius-ref.html b/layout/reftests/table-bordercollapse/bc_borderradius-ref.html new file mode 100644 index 000000000..c7b041f79 --- /dev/null +++ b/layout/reftests/table-bordercollapse/bc_borderradius-ref.html @@ -0,0 +1,17 @@ + + +
 
 
b
+ + + +
diff --git a/layout/reftests/table-bordercollapse/bc_borderradius.html b/layout/reftests/table-bordercollapse/bc_borderradius.html new file mode 100644 index 000000000..3ae2a89d8 --- /dev/null +++ b/layout/reftests/table-bordercollapse/bc_borderradius.html @@ -0,0 +1,18 @@ + + + + + + +
diff --git a/layout/reftests/table-bordercollapse/reftest.list b/layout/reftests/table-bordercollapse/reftest.list index 8356dc54b..5ca6f305a 100644 --- a/layout/reftests/table-bordercollapse/reftest.list +++ b/layout/reftests/table-bordercollapse/reftest.list @@ -20,6 +20,7 @@ == bc_dyn_table3.html bc_dyn_table3_ref.html == bc_borderoffset1.html bc_borderoffset1_ref.html == bc_borderoffset2.html bc_borderoffset2_ref.html +== bc_borderradius.html bc_borderradius-ref.html == frame_above_rules_all.html frame_above_rules_all_ref.html == frame_above_rules_cols.html frame_above_rules_cols_ref.html == frame_above_rules_groups.html frame_above_rules_groups_ref.html @@ -104,4 +105,5 @@ fuzzy(255,40) == border-style-outset-becomes-groove.html border-style-outset-bec # So get 40 pixels of fuzz, 20 at each beveled corner (because the border width # is 20px). fuzzy(255,40) == border-style-inset-becomes-ridge.html border-style-inset-becomes-ridge-ref.html -fuzzy(2,8301) == 1324524.html 1324524-ref.html +fuzzy(2,11000) == 1324524.html 1324524-ref.html + -- cgit v1.2.3 From ce11d5cae866f24b8f7435cdc3725cfd2748595b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 19:09:47 +0100 Subject: Issue #146 - Part 5: Treat table row groups as containing blocks. This aligns our behavior with Gecko/Blink. --- layout/generic/StickyScrollContainer.cpp | 8 ++++++++ layout/generic/nsFrame.cpp | 3 +++ 2 files changed, 11 insertions(+) (limited to 'layout') diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index ca68992c3..ff8ebcfef 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -176,6 +176,14 @@ StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, nsRect rect = nsLayoutUtils::GetAllInFlowRectsUnion(aFrame, aFrame->GetParent()); + // Note: Table row groups aren't supposed to be containing blocks, but we treat + // them as such anyway. + // Not having this basically disables position:sticky on table cells, which + // would be really unfortunate, and doesn't match what other browsers do. + if (cbFrame != scrolledFrame && cbFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { + cbFrame = cbFrame->GetContainingBlock(); + } + // Containing block limits for the position of aFrame relative to its parent. // The margin box of the sticky element stays within the content box of the // contaning-block element. diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index a531dea07..d4bcf22ed 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -6629,6 +6629,9 @@ GetNearestBlockContainer(nsIFrame* frame) // Since the parent of such a block is either a normal block or // another such pseudo, this shouldn't cause anything bad to happen. // Also the anonymous blocks inside table cells are not containing blocks. + // + // If we ever start skipping table row groups from being containing blocks, + // we need to remove the containing block assignment in StickyScrollContainer . while (frame->IsFrameOfType(nsIFrame::eLineParticipant) || frame->IsBlockWrapper() || // Table rows are not containing blocks either -- cgit v1.2.3 From 5ab2da700448caf181dae7dec2f53997faf118ea Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 19:43:51 +0100 Subject: Issue #146 - Part 6: Allow `position: sticky` on table elements. --- layout/base/RestyleManagerBase.cpp | 9 --------- layout/generic/StickyScrollContainer.cpp | 2 +- layout/generic/nsFrame.cpp | 5 +---- layout/tables/nsTableRowFrame.cpp | 11 +++++------ 4 files changed, 7 insertions(+), 20 deletions(-) (limited to 'layout') diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp index 6770f9464..6ef048a19 100644 --- a/layout/base/RestyleManagerBase.cpp +++ b/layout/base/RestyleManagerBase.cpp @@ -474,15 +474,6 @@ RecomputePosition(nsIFrame* aFrame) if (display->IsRelativelyPositionedStyle()) { // Move the frame if (display->mPosition == NS_STYLE_POSITION_STICKY) { - if (display->IsInnerTableStyle()) { - // We don't currently support sticky positioning of inner table - // elements (bug 975644). Bail. - // - // When this is fixed, remove the null-check for the computed - // offsets in nsTableRowFrame::ReflowChildren. - return true; - } - // Update sticky positioning for an entire element at once, starting with // the first continuation or ib-split sibling. // It's rare that the frame we already have isn't already the first diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index ff8ebcfef..c5ed44e92 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -45,7 +45,7 @@ StickyScrollContainer::GetStickyScrollContainerForFrame(nsIFrame* aFrame) // return nullptr; } - auto frame = static_cast(do_QueryFrame(scrollFrame)); + nsIFrame* frame = do_QueryFrame(scrollFrame); StickyScrollContainer* s = frame->GetProperty(StickyScrollContainerProperty()); if (!s) { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index d4bcf22ed..bbbb5c332 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -562,15 +562,12 @@ nsFrame::Init(nsIContent* aContent, } if (disp->mPosition == NS_STYLE_POSITION_STICKY && !aPrevInFlow && - !(mState & NS_FRAME_IS_NONDISPLAY) && - !disp->IsInnerTableStyle()) { + !(mState & NS_FRAME_IS_NONDISPLAY)) { // Note that we only add first continuations, but we really only // want to add first continuation-or-ib-split-siblings. But since we // don't yet know if we're a later part of a block-in-inline split, // we'll just add later members of a block-in-inline split here, and // then StickyScrollContainer will remove them later. - // We don't currently support relative positioning of inner table - // elements (bug 35168), so exclude them from sticky positioning too. StickyScrollContainer* ssc = StickyScrollContainer::GetStickyScrollContainerForFrame(this); if (ssc) { diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 05b9deee9..ea2477b73 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -926,12 +926,11 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, // be merged into the else below if we can.) nsMargin* computedOffsetProp = kidFrame->GetProperty(nsIFrame::ComputedOffsetProperty()); - // Bug 975644: a position:sticky kid can end up with a null - // property value here. - LogicalMargin computedOffsets(wm, computedOffsetProp ? - *computedOffsetProp : nsMargin()); - ReflowInput::ApplyRelativePositioning(kidFrame, wm, computedOffsets, - &kidPosition, containerSize); + + // On our fist reflow sticky children may not have the property yet (we + // need to reflow the children first to size the scroll frame). + LogicalMargin computedOffsets(wm, computedOffsetProp ? *computedOffsetProp : nsMargin()); + ReflowInput::ApplyRelativePositioning(kidFrame, wm, computedOffsets, &kidPosition, containerSize); } // In vertical-rl mode, we are likely to have containerSize.width = 0 -- cgit v1.2.3 From 76052e837cd49879e2e738e575984c340f176859 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 3 Nov 2019 19:45:49 +0100 Subject: Issue #146 - Part 7: Remove no longer relevant reftest. --- .../position-sticky/inner-table-1-ref.html | 26 ---------------- layout/reftests/position-sticky/inner-table-1.html | 35 ---------------------- layout/reftests/position-sticky/reftest.list | 1 - 3 files changed, 62 deletions(-) delete mode 100644 layout/reftests/position-sticky/inner-table-1-ref.html delete mode 100644 layout/reftests/position-sticky/inner-table-1.html (limited to 'layout') diff --git a/layout/reftests/position-sticky/inner-table-1-ref.html b/layout/reftests/position-sticky/inner-table-1-ref.html deleted file mode 100644 index 379841fae..000000000 --- a/layout/reftests/position-sticky/inner-table-1-ref.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -
a
b
c
d
- - diff --git a/layout/reftests/position-sticky/inner-table-1.html b/layout/reftests/position-sticky/inner-table-1.html deleted file mode 100644 index 212e658fd..000000000 --- a/layout/reftests/position-sticky/inner-table-1.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - CSS Test: Sticky Positioning - inner table elements - - - - - - - - - - - - - - - - - - - - - -
a
b
c
d
- - diff --git a/layout/reftests/position-sticky/reftest.list b/layout/reftests/position-sticky/reftest.list index 2705d08fd..01e7b1638 100644 --- a/layout/reftests/position-sticky/reftest.list +++ b/layout/reftests/position-sticky/reftest.list @@ -48,4 +48,3 @@ fails == column-contain-1a.html column-contain-1-ref.html fuzzy-if(skiaContent,1,22) fuzzy-if(winWidget&&!layersGPUAccelerated,116,1320) fuzzy-if(Android,8,1533) == block-in-inline-2.html block-in-inline-2-ref.html fuzzy-if(Android,8,630) fuzzy-if(OSX>=1008,1,11) fuzzy-if(skiaContent,1,220) fuzzy-if(winWidget&&!layersGPUAccelerated,116,1320) == block-in-inline-3.html block-in-inline-3-ref.html == block-in-inline-continuations.html block-in-inline-continuations-ref.html -fuzzy-if(winWidget&&!layersGPUAccelerated,140,140) == inner-table-1.html inner-table-1-ref.html -- cgit v1.2.3 From 56de283899bc91f7110aba58a3ca174c10852683 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 14 Nov 2019 09:07:29 +0100 Subject: Issue #1288 - Part 1a: Update brotli to 1.0.7 This also reorganizes the exports in the build system to use `brotli/` as include directory. --- layout/inspector/nsFontFace.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'layout') diff --git a/layout/inspector/nsFontFace.cpp b/layout/inspector/nsFontFace.cpp index a4a9231e2..abf9f6439 100644 --- a/layout/inspector/nsFontFace.cpp +++ b/layout/inspector/nsFontFace.cpp @@ -9,7 +9,7 @@ #include "gfxUserFontSet.h" #include "nsFontFaceLoader.h" #include "mozilla/gfx/2D.h" -#include "decode.h" +#include "brotli/decode.h" #include "zlib.h" #include "mozilla/dom/FontFaceSet.h" @@ -208,10 +208,10 @@ nsFontFace::GetMetadata(nsAString & aMetadata) case gfxUserFontData::kBrotliCompression: { size_t decodedSize = userFontData->mMetaOrigLen; - if (BrotliDecompressBuffer(userFontData->mMetadata.Length(), - userFontData->mMetadata.Elements(), - &decodedSize, - (uint8_t*)str.BeginWriting()) == 1 && + if (BrotliDecoderDecompress(userFontData->mMetadata.Length(), + userFontData->mMetadata.Elements(), + &decodedSize, + (uint8_t*)str.BeginWriting()) == 1 && decodedSize == userFontData->mMetaOrigLen) { AppendUTF8toUTF16(str, aMetadata); } -- cgit v1.2.3 From 0f8691a48869932cd3de5195f5211c25e4691b21 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 14 Nov 2019 10:07:01 +0100 Subject: Issue #1288 - Part 4: Update the OpenType Sanitizer component to 8.0.0 --- layout/reftests/fonts/header-totalsfntsize-001.woff2 | Bin 980 -> 980 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'layout') diff --git a/layout/reftests/fonts/header-totalsfntsize-001.woff2 b/layout/reftests/fonts/header-totalsfntsize-001.woff2 index 738560518..e02a0d867 100644 Binary files a/layout/reftests/fonts/header-totalsfntsize-001.woff2 and b/layout/reftests/fonts/header-totalsfntsize-001.woff2 differ -- cgit v1.2.3 From 7070dddb4b8738ca983a12bc6e22b6e7418b2428 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Fri, 29 Nov 2019 00:19:03 +0100 Subject: Simplify the overflow child frame reparenting in nsInlineFrame::DestroyFrom. --- layout/generic/nsInlineFrame.cpp | 6 ++---- layout/generic/nsInlineFrame.h | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'layout') diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 54d93c85a..5a04f0cd1 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -199,8 +199,7 @@ nsInlineFrame::DestroyFrom(nsIFrame* aDestructRoot) // Fixup the parent pointers for any child frames on the OverflowList. // nsIFrame::DestroyFrom depends on that to find the sticky scroll // container (an ancestor). - nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this); - DrainSelfOverflowListInternal(eForDestroy, lineContainer); + overflowFrames->ApplySetParent(this); } nsContainerFrame::DestroyFrom(aDestructRoot); } @@ -508,8 +507,7 @@ nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags, if (aLineContainer && aLineContainer->GetPrevContinuation()) { ReparentFloatsForInlineChild(aLineContainer, firstChild, true); } - const bool doReparentSC = - (aFlags & eInFirstLine) && !(aFlags & eForDestroy); + const bool doReparentSC = (aFlags & eInFirstLine); RestyleManagerHandle restyleManager = PresContext()->RestyleManager(); for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) { f->SetParent(this); diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 00f89065c..a9679e93f 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -175,9 +175,6 @@ private: enum DrainFlags { eDontReparentFrames = 1, // skip reparenting the overflow list frames eInFirstLine = 2, // the request is for an inline descendant of a nsFirstLineFrame - eForDestroy = 4, // the request is from DestroyFrom; in this case we do the - // minimal work required since the frame is about to be - // destroyed (just fixup parent pointers) }; /** * Move any frames on our overflow list to the end of our principal list. -- cgit v1.2.3 From 6ea8e51aaa192d920ffd6b8a7d4cc4e998d7222a Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Fri, 29 Nov 2019 10:48:50 +0100 Subject: Remove unnecessary calls to ReparentFloatsForInlineChild in nsInlineFrame. --- layout/generic/BlockReflowInput.cpp | 2 ++ layout/generic/nsInlineFrame.cpp | 49 ++++++------------------------------- layout/generic/nsInlineFrame.h | 4 +-- 3 files changed, 10 insertions(+), 45 deletions(-) (limited to 'layout') diff --git a/layout/generic/BlockReflowInput.cpp b/layout/generic/BlockReflowInput.cpp index 10084fd8b..86248ac14 100644 --- a/layout/generic/BlockReflowInput.cpp +++ b/layout/generic/BlockReflowInput.cpp @@ -716,6 +716,8 @@ FloatMarginISize(const ReflowInput& aCBReflowInput, bool BlockReflowInput::FlowAndPlaceFloat(nsIFrame* aFloat) { + MOZ_ASSERT(aFloat->GetParent() == mBlock); + WritingMode wm = mReflowInput.GetWritingMode(); // Save away the Y coordinate before placing the float. We will // restore mBCoord at the end after placing the float. This is diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 5a04f0cd1..7e188c247 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -376,8 +376,6 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, bool lazilySetParentPointer = false; - nsIFrame* lineContainer = aReflowInput.mLineLayout->LineContainerFrame(); - // Check for an overflow list with our prev-in-flow nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow(); if (prevInFlow) { @@ -403,12 +401,6 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, mFrames.SetFrames(*prevOverflowFrames); lazilySetParentPointer = true; } else { - // Assign all floats to our block if necessary - if (lineContainer && lineContainer->GetPrevContinuation()) { - ReparentFloatsForInlineChild(lineContainer, - prevOverflowFrames->FirstChild(), - true); - } // Insert the new frames at the beginning of the child list // and set their parent pointer const nsFrameList::Slice& newFrames = @@ -442,14 +434,13 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, if (aReflowInput.mLineLayout->GetInFirstLine()) { flags = DrainFlags(flags | eInFirstLine); } - DrainSelfOverflowListInternal(flags, lineContainer); + DrainSelfOverflowListInternal(flags); } - // Set our own reflow state (additional state above and beyond - // aReflowInput) + // Set our own reflow state (additional state above and beyond aReflowInput) InlineReflowInput irs; irs.mPrevFrame = nullptr; - irs.mLineContainer = lineContainer; + irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame(); irs.mLineLayout = aReflowInput.mLineLayout; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); irs.mSetParentPointer = lazilySetParentPointer; @@ -494,8 +485,7 @@ nsInlineFrame::AttributeChanged(int32_t aNameSpaceID, } bool -nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags, - nsIFrame* aLineContainer) +nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags) { AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames()); if (overflowFrames) { @@ -504,9 +494,6 @@ nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags, // correct parent pointer. This is sometimes skipped by Reflow. if (!(aFlags & eDontReparentFrames)) { nsIFrame* firstChild = overflowFrames->FirstChild(); - if (aLineContainer && aLineContainer->GetPrevContinuation()) { - ReparentFloatsForInlineChild(aLineContainer, firstChild, true); - } const bool doReparentSC = (aFlags & eInFirstLine); RestyleManagerHandle restyleManager = PresContext()->RestyleManager(); for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) { @@ -537,7 +524,7 @@ nsInlineFrame::DrainSelfOverflowList() break; } } - return DrainSelfOverflowListInternal(flags, lineContainer); + return DrainSelfOverflowListInternal(flags); } /* virtual */ bool @@ -606,23 +593,8 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, while (frame) { // Check if we should lazily set the child frame's parent pointer. if (irs.mSetParentPointer) { - bool havePrevBlock = - irs.mLineContainer && irs.mLineContainer->GetPrevContinuation(); nsIFrame* child = frame; do { - // If our block is the first in flow, then any floats under the pulled - // frame must already belong to our block. - if (havePrevBlock) { - // This has to happen before we update frame's parent; we need to - // know frame's ancestry under its old block. - // The blockChildren.ContainsFrame check performed by - // ReparentFloatsForInlineChild here may be slow, but we can't - // easily avoid it because we don't know where 'frame' originally - // came from. If we really really have to optimize this we could - // cache whether frame->GetParent() is under its containing blocks - // overflowList or not. - ReparentFloatsForInlineChild(irs.mLineContainer, child, false); - } child->SetParent(this); if (inFirstLine) { restyleManager->ReparentStyleContext(child); @@ -1098,20 +1070,13 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext, return; // XXX does this happen? why? } - nsIFrame* lineContainer = aReflowInput.mLineLayout->LineContainerFrame(); - // Check for an overflow list with our prev-in-flow nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow(); if (prevInFlow) { AutoFrameListPtr prevOverflowFrames(aPresContext, prevInFlow->StealOverflowFrames()); if (prevOverflowFrames) { - // Assign all floats to our block if necessary - if (lineContainer && lineContainer->GetPrevContinuation()) { - ReparentFloatsForInlineChild(lineContainer, - prevOverflowFrames->FirstChild(), - true); - } + // Reparent the new frames and their style contexts. const nsFrameList::Slice& newFrames = mFrames.InsertFrames(this, nullptr, *prevOverflowFrames); ReparentChildListStyle(aPresContext, newFrames, this); @@ -1125,7 +1090,7 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext, // aReflowInput) InlineReflowInput irs; irs.mPrevFrame = nullptr; - irs.mLineContainer = lineContainer; + irs.mLineContainer = aReflowInput.mLineLayout->LineContainerFrame(); irs.mLineLayout = aReflowInput.mLineLayout; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index a9679e93f..36df6be93 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -179,11 +179,9 @@ private: /** * Move any frames on our overflow list to the end of our principal list. * @param aFlags one or more of the above DrainFlags - * @param aLineContainer the nearest line container ancestor * @return true if there were any overflow frames */ - bool DrainSelfOverflowListInternal(DrainFlags aFlags, - nsIFrame* aLineContainer); + bool DrainSelfOverflowListInternal(DrainFlags aFlags); protected: nscoord mBaseline; }; -- cgit v1.2.3 From 0f001155aa004f1a6679f386d49f64306fb54ab1 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 1 Dec 2019 06:20:05 +0100 Subject: Issue #1308 - Create nsDisplayTableBackgroundColor to avoid display list collisions when processing the background color of a table. This is effectively #146 Part 3c to go along with the other 2 there. This resolves #1308. --- layout/base/nsDisplayList.cpp | 19 ++++++++++++++++--- layout/base/nsDisplayList.h | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) (limited to 'layout') diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 1579e6970..8a34d108f 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2703,9 +2703,22 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil bg->BottomLayer(), bgRect, useWillPaintBorderOptimization); } - bgItemList.AppendNewToTop( - new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bgRect, bg, - drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0))); + if (aSecondaryReferenceFrame) { + bgItemList.AppendNewToTop( + new (aBuilder) nsDisplayTableBackgroundColor(aBuilder, + aSecondaryReferenceFrame, + bgRect, + bg, + drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0), + aFrame)); + } else { + bgItemList.AppendNewToTop( + new (aBuilder) nsDisplayBackgroundColor(aBuilder, + aFrame, + bgRect, + bg, + drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0))); + } } if (isThemed) { diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index e9047b113..9cee7b517 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3015,6 +3015,27 @@ protected: mozilla::gfx::Color mColor; }; +class nsDisplayTableBackgroundColor : public nsDisplayBackgroundColor +{ +public: + nsDisplayTableBackgroundColor(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + const nsRect& aBackgroundRect, + const nsStyleBackground* aBackgroundStyle, + nscolor aColor, + nsIFrame* aAncestorFrame) + : nsDisplayBackgroundColor(aBuilder, aFrame, aBackgroundRect, aBackgroundStyle, aColor) + , mTableType(GetTableTypeFromFrame(aAncestorFrame)) + { } + + virtual uint32_t GetPerFrameKey() override { + return (static_cast(mTableType) << nsDisplayItem::TYPE_BITS) | + nsDisplayItem::GetPerFrameKey(); + } +protected: + TableType mTableType; +}; + class nsDisplayClearBackground : public nsDisplayItem { public: -- cgit v1.2.3 From cb65f6d10c30e21808068282eb7695277cd68b89 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 1 Dec 2019 06:31:26 +0100 Subject: Issue #1309 - Fix handling of display rows where the elements are not forming a monotonically increasing sequence (e.g. with position:sticky) Relative positioning can cause table parts to move, which can cause issues with the cursor position to know which rows can be skipped. To make this work, use the max difference between the frame's rect and the union of the frame's "normal" position and the overflow rect to cover the area of relatively positioned elements even if they are out of order. This resolves #1309. --- layout/tables/nsTableRowGroupFrame.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'layout') diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 3e4f60f62..f613c8b79 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -164,7 +164,7 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, // Don't try to use the row cursor if we have to descend into placeholders; // we might have rows containing placeholders, where the row's overflow // area doesn't intersect the dirty rect but we need to descend into the row - // to see out of flows. + // to see out-of-flows. // Note that we really want to check ShouldDescendIntoFrame for all // the rows in |f|, but that's exactly what we're trying to avoid, so we // approximate it by checking it for |f|: if it's true for any row @@ -173,11 +173,11 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, nullptr : f->GetFirstRowContaining(aDirtyRect.y, &overflowAbove); if (kid) { - // have a cursor, use it + // If we have a cursor, use it while (kid) { - if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost() && - kid->GetNormalRect().y - overflowAbove >= aDirtyRect.YMost()) + if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost()) { break; + } f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); kid = kid->GetNextSibling(); } @@ -1911,12 +1911,12 @@ nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) // encountering a row whose overflowArea.YMost() is <= aY but which has // a row above it containing cell(s) that span to include aY. while (cursorIndex > 0 && - cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow > aY) { + cursorFrame->GetRect().YMost() + property->mOverflowBelow > aY) { --cursorIndex; cursorFrame = property->mFrames[cursorIndex]; } while (cursorIndex + 1 < frameCount && - cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow <= aY) { + cursorFrame->GetRect().YMost() + property->mOverflowBelow <= aY) { ++cursorIndex; cursorFrame = property->mFrames[cursorIndex]; } @@ -1929,13 +1929,11 @@ nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) bool nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame) { - // Relative positioning can cause table parts to move, but we will still paint - // the backgrounds for the parts under them at their 'normal' position. That - // means that we must consider the overflow rects at both positions. For - // example, if we use relative positioning to move a row-spanning cell, we - // will still paint the row background for that cell at its normal position, - // which will overflow the row. - // XXX(seth): This probably isn't correct in the presence of transforms. + // Relative positioning can cause table parts to move, which can cause issues + // with the cursor position to know which rows can be skipped. + // To make this work, use the max difference between the frame's rect and the + // union of the frame's "normal" position and the overflow rect to cover the + // area of relatively positioned elements even if they are out of order. nsRect positionedOverflowRect = aFrame->GetVisualOverflowRect(); nsPoint positionedToNormal = aFrame->GetNormalPosition() - aFrame->GetPosition(); nsRect normalOverflowRect = positionedOverflowRect + positionedToNormal; -- cgit v1.2.3 From 44967b330d3aec6959410c3f54d9cbcc04059aac Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 6 Dec 2019 13:42:37 +0100 Subject: Check if we're already at the end of the frame's content. --- layout/generic/nsTextFrame.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'layout') diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 0641c7439..59ef020ce 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -7525,7 +7525,8 @@ nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset, gfxSkipCharsIterator nextIter(iter); nextIter.AdvanceOriginal(1); if (!nextIter.IsOriginalCharSkipped() && - !mTextRun->IsClusterStart(nextIter.GetSkippedOffset())) { + !mTextRun->IsClusterStart(nextIter.GetSkippedOffset()) && + nextIter.GetOriginalOffset() < kContentEnd) { FindClusterEnd(mTextRun, kContentEnd, &nextIter); } -- cgit v1.2.3