зеркало из 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
|
nsDisplayListBuilder::AutoBuildingDisplayList
|
||||||
buildingDisplayList(aBuilder, this, dirtyRect, true);
|
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);
|
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;
|
bool clearClip = false;
|
||||||
if (isTransformed || usingSVGEffects || useFixedPosition || useStickyPosition) {
|
if (clipCapturedBy != ContainerItemType::eNone) {
|
||||||
// We don't need to pass ancestor clipping down to our children;
|
// We don't need to pass ancestor clipping down to our children;
|
||||||
// everything goes inside a display item's child list, and the display
|
// everything goes inside a display item's child list, and the display
|
||||||
// item itself will be clipped.
|
// item itself will be clipped.
|
||||||
|
@ -2411,18 +2460,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
containerItemScrollClip));
|
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
|
/* 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
|
* (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
|
* item even if resultList is empty, since a filter can produce graphical
|
||||||
* output even if the element being filtered wouldn't otherwise do so.
|
* output even if the element being filtered wouldn't otherwise do so.
|
||||||
*/
|
*/
|
||||||
if (usingSVGEffects) {
|
if (usingSVGEffects) {
|
||||||
|
if (clipCapturedBy == ContainerItemType::eSVGEffects) {
|
||||||
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
|
}
|
||||||
// Revert to the post-filter dirty rect.
|
// Revert to the post-filter dirty rect.
|
||||||
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
|
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
|
||||||
/* List now emptied, so add the new list to the top. */
|
/* List now emptied, so add the new list to the top. */
|
||||||
|
@ -2488,19 +2534,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
resultList.AppendToTop(&participants);
|
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 (isTransformed && !resultList.IsEmpty()) {
|
||||||
// Restore clip state now so nsDisplayTransform is clipped properly.
|
if (clipCapturedBy == ContainerItemType::eTransform) {
|
||||||
if (!hasPerspective && !useFixedPosition && !useStickyPosition && !needsLayerForMask) {
|
// Restore clip state now so nsDisplayTransform is clipped properly.
|
||||||
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
}
|
}
|
||||||
// Revert to the dirtyrect coming in from the parent, without our transform
|
// Revert to the dirtyrect coming in from the parent, without our transform
|
||||||
|
@ -2529,7 +2565,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasPerspective) {
|
if (hasPerspective) {
|
||||||
if (!useFixedPosition && !useStickyPosition && !needsLayerForMask) {
|
if (clipCapturedBy == ContainerItemType::ePerspective) {
|
||||||
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
}
|
}
|
||||||
resultList.AppendNewToTop(
|
resultList.AppendNewToTop(
|
||||||
|
@ -2539,11 +2575,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useFixedPosition || useStickyPosition || needsLayerForMask) {
|
if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
|
||||||
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
}
|
|
||||||
|
|
||||||
if (needsLayerForMask) {
|
|
||||||
resultList.AppendNewToTop(
|
resultList.AppendNewToTop(
|
||||||
new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
|
new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
|
||||||
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
|
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 we have sticky positioning, wrap it in a sticky position item.
|
||||||
*/
|
*/
|
||||||
if (useFixedPosition) {
|
if (useFixedPosition) {
|
||||||
|
if (clipCapturedBy == ContainerItemType::eFixedPosition) {
|
||||||
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
|
}
|
||||||
resultList.AppendNewToTop(
|
resultList.AppendNewToTop(
|
||||||
new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
|
new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
|
||||||
} else if (useStickyPosition) {
|
} else if (useStickyPosition) {
|
||||||
|
if (clipCapturedBy == ContainerItemType::eStickyPosition) {
|
||||||
|
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||||
|
}
|
||||||
resultList.AppendNewToTop(
|
resultList.AppendNewToTop(
|
||||||
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
|
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче