Bug 1298209 - Make clip capturing easier to understand. r=mattwoodrow

MozReview-Commit-ID: 6OmdH7WoFma

--HG--
extra : rebase_source : 9fc53828b07034b26c6a6075d34bb4c2c4cb1110
This commit is contained in:
Markus Stange 2016-08-23 17:34:33 -04:00
Родитель 1eb29de8a4
Коммит 81fe352e5f
1 изменённых файлов: 63 добавлений и 24 удалений

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

@ -2271,10 +2271,59 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsDisplayListBuilder::AutoBuildingDisplayList
buildingDisplayList(aBuilder, this, dirtyRect, true);
// Depending on the effects that are applied to this frame, we can create
// multiple container display items and wrap them around our contents.
// This enum lists all the potential container display items, in the order
// outside to inside.
enum class ContainerItemType : uint8_t {
eNone = 0,
eOwnLayerIfNeeded,
eBlendMode,
eFixedPosition,
eStickyPosition,
eOwnLayerForTransformWithRoundedClip,
ePerspective,
eTransform,
eSeparatorTransforms,
eOpacity,
eSVGEffects,
eBlendContainer
};
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// If there is a current clip, then depending on the container items we
// create, different things can happen to it. Some container items simply
// propagate the clip to their children and aren't clipped themselves.
// But other container items, especially those that establish a different
// geometry for their contents (e.g. transforms), capture the clip on
// themselves and unset the clip for their contents. If we create more than
// one of those container items, the clip will be captured on the outermost
// one and the inner container items will be unclipped.
ContainerItemType clipCapturedBy = ContainerItemType::eNone;
if (useFixedPosition) {
clipCapturedBy = ContainerItemType::eFixedPosition;
} else if (useStickyPosition) {
clipCapturedBy = ContainerItemType::eStickyPosition;
} else if (isTransformed) {
if ((hasPerspective || extend3DContext) && clipState.SavedStateHasRoundedCorners()) {
// If we're creating an nsDisplayTransform item that is going to combine
// its transform with its children (preserve-3d or perspective), then we
// can't have an intermediate surface. Mask layers force an intermediate
// surface, so if we're going to need both then create a separate
// wrapping layer for the mask.
clipCapturedBy = ContainerItemType::eOwnLayerForTransformWithRoundedClip;
} else if (hasPerspective) {
clipCapturedBy = ContainerItemType::ePerspective;
} else {
clipCapturedBy = ContainerItemType::eTransform;
}
} else if (usingSVGEffects) {
clipCapturedBy = ContainerItemType::eSVGEffects;
}
bool clearClip = false;
if (isTransformed || usingSVGEffects || useFixedPosition || useStickyPosition) {
if (clipCapturedBy != ContainerItemType::eNone) {
// We don't need to pass ancestor clipping down to our children;
// everything goes inside a display item's child list, and the display
// item itself will be clipped.
@ -2411,18 +2460,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
containerItemScrollClip));
}
if (!isTransformed && !useFixedPosition && !useStickyPosition) {
// Restore saved clip state now so that any display items we create below
// are clipped properly.
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
/* If there are any SVG effects, wrap the list up in an SVG effects item
* (which also handles CSS group opacity). Note that we create an SVG effects
* item even if resultList is empty, since a filter can produce graphical
* output even if the element being filtered wouldn't otherwise do so.
*/
if (usingSVGEffects) {
if (clipCapturedBy == ContainerItemType::eSVGEffects) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
// Revert to the post-filter dirty rect.
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
/* List now emptied, so add the new list to the top. */
@ -2488,19 +2534,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
resultList.AppendToTop(&participants);
}
/* If we're creating an nsDisplayTransform item that is going to combine its transform
* with its children (preserve-3d or perspective), then we can't have an intermediate
* surface. Mask layers force an intermediate surface, so if we're going to need both
* then create a separate wrapping layer for the mask.
*/
bool needsLayerForMask = isTransformed && (extend3DContext || hasPerspective) &&
clipState.SavedStateHasRoundedCorners();
NS_ASSERTION(!Combines3DTransformWithAncestors() || !clipState.SavedStateHasRoundedCorners(),
"Can't support mask layers on intermediate preserve-3d frames");
if (isTransformed && !resultList.IsEmpty()) {
if (clipCapturedBy == ContainerItemType::eTransform) {
// Restore clip state now so nsDisplayTransform is clipped properly.
if (!hasPerspective && !useFixedPosition && !useStickyPosition && !needsLayerForMask) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
// Revert to the dirtyrect coming in from the parent, without our transform
@ -2529,7 +2565,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
}
if (hasPerspective) {
if (!useFixedPosition && !useStickyPosition && !needsLayerForMask) {
if (clipCapturedBy == ContainerItemType::ePerspective) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
resultList.AppendNewToTop(
@ -2539,11 +2575,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
}
}
if (useFixedPosition || useStickyPosition || needsLayerForMask) {
if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
if (needsLayerForMask) {
resultList.AppendNewToTop(
new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
@ -2553,9 +2586,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* If we have sticky positioning, wrap it in a sticky position item.
*/
if (useFixedPosition) {
if (clipCapturedBy == ContainerItemType::eFixedPosition) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
resultList.AppendNewToTop(
new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
} else if (useStickyPosition) {
if (clipCapturedBy == ContainerItemType::eStickyPosition) {
clipState.ExitStackingContextContents(&containerItemScrollClip);
}
resultList.AppendNewToTop(
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
}