зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1298209 - Make clip capturing easier to understand. r=mattwoodrow
MozReview-Commit-ID: 6OmdH7WoFma --HG-- extra : rebase_source : 9fc53828b07034b26c6a6075d34bb4c2c4cb1110
This commit is contained in:
Родитель
1eb29de8a4
Коммит
81fe352e5f
|
@ -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));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче