mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
6f24092aae
The displayport clip that is applied to sticky items from the enclosing scrollframe can cause sticky items to checkerboard even when they might reasonably be left visible. This is because the displayport clip moves as the enclosing scrollframe is scrolled, but sticky items may remain fixed during such scrolling. The displayport clip can therefore clip out sticky items even if they are "stuck" and should be user-visible. This patch sets a flag to identify when a sticky item is being clipped by the displayport clip, and ensures that it doesn't actually get clipped. In the case where other clips are being applied to the sticky item, we leave the clips unaffected. This allows for other enclosing elements to clip the sticky item as before. Differential Revision: https://phabricator.services.mozilla.com/D68582 --HG-- extra : moz-landing-system : lando
150 lines
5.6 KiB
C++
150 lines
5.6 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "DisplayListClipState.h"
|
|
|
|
#include "nsDisplayList.h"
|
|
|
|
namespace mozilla {
|
|
|
|
const DisplayItemClipChain* DisplayListClipState::GetCurrentCombinedClipChain(
|
|
nsDisplayListBuilder* aBuilder) {
|
|
if (mCurrentCombinedClipChainIsValid) {
|
|
return mCurrentCombinedClipChain;
|
|
}
|
|
if (!mClipChainContentDescendants && !mClipChainContainingBlockDescendants) {
|
|
mCurrentCombinedClipChain = nullptr;
|
|
mCurrentCombinedClipChainIsValid = true;
|
|
return nullptr;
|
|
}
|
|
|
|
mCurrentCombinedClipChain = aBuilder->CreateClipChainIntersection(
|
|
mCurrentCombinedClipChain, mClipChainContentDescendants,
|
|
mClipChainContainingBlockDescendants);
|
|
mCurrentCombinedClipChainIsValid = true;
|
|
return mCurrentCombinedClipChain;
|
|
}
|
|
|
|
static void ApplyClip(nsDisplayListBuilder* aBuilder,
|
|
const DisplayItemClipChain*& aClipToModify,
|
|
const ActiveScrolledRoot* aASR,
|
|
DisplayItemClipChain& aClipChainOnStack) {
|
|
aClipChainOnStack.mASR = aASR;
|
|
if (aClipToModify && aClipToModify->mASR == aASR) {
|
|
// Intersect with aClipToModify and replace the clip chain item.
|
|
aClipChainOnStack.mClip.IntersectWith(aClipToModify->mClip);
|
|
aClipChainOnStack.mParent = aClipToModify->mParent;
|
|
aClipToModify = &aClipChainOnStack;
|
|
} else if (!aClipToModify ||
|
|
ActiveScrolledRoot::IsAncestor(aClipToModify->mASR, aASR)) {
|
|
// Add a new clip chain item at the bottom.
|
|
aClipChainOnStack.mParent = aClipToModify;
|
|
aClipToModify = &aClipChainOnStack;
|
|
} else {
|
|
// We need to insert / intersect a DisplayItemClipChain in the middle of the
|
|
// aClipToModify chain. This is a very rare case.
|
|
// Find the common ancestor and have the builder create the
|
|
// DisplayItemClipChain intersection. This will create new
|
|
// DisplayItemClipChain objects for all descendants of ancestorSC and we
|
|
// will not hold on to a pointer to aClipChainOnStack.
|
|
const DisplayItemClipChain* ancestorSC = aClipToModify;
|
|
while (ancestorSC &&
|
|
ActiveScrolledRoot::IsAncestor(aASR, ancestorSC->mASR)) {
|
|
ancestorSC = ancestorSC->mParent;
|
|
}
|
|
ancestorSC = aBuilder->CopyWholeChain(ancestorSC);
|
|
aClipChainOnStack.mParent = nullptr;
|
|
aClipToModify = aBuilder->CreateClipChainIntersection(
|
|
ancestorSC, aClipToModify, &aClipChainOnStack);
|
|
}
|
|
}
|
|
|
|
void DisplayListClipState::ClipContainingBlockDescendants(
|
|
nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
|
|
DisplayItemClipChain& aClipChainOnStack) {
|
|
if (aRadii) {
|
|
aClipChainOnStack.mClip.SetTo(aRect, aRadii);
|
|
} else {
|
|
aClipChainOnStack.mClip.SetTo(aRect);
|
|
}
|
|
const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
|
|
ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr,
|
|
aClipChainOnStack);
|
|
InvalidateCurrentCombinedClipChain(asr);
|
|
}
|
|
|
|
void DisplayListClipState::ClipContentDescendants(
|
|
nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
|
|
DisplayItemClipChain& aClipChainOnStack) {
|
|
if (aRadii) {
|
|
aClipChainOnStack.mClip.SetTo(aRect, aRadii);
|
|
} else {
|
|
aClipChainOnStack.mClip.SetTo(aRect);
|
|
}
|
|
const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
|
|
ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
|
|
InvalidateCurrentCombinedClipChain(asr);
|
|
}
|
|
|
|
void DisplayListClipState::ClipContentDescendants(
|
|
nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|
const nsRect& aRoundedRect, const nscoord* aRadii,
|
|
DisplayItemClipChain& aClipChainOnStack) {
|
|
if (aRadii) {
|
|
aClipChainOnStack.mClip.SetTo(aRect, aRoundedRect, aRadii);
|
|
} else {
|
|
nsRect intersect = aRect.Intersect(aRoundedRect);
|
|
aClipChainOnStack.mClip.SetTo(intersect);
|
|
}
|
|
const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
|
|
ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
|
|
InvalidateCurrentCombinedClipChain(asr);
|
|
}
|
|
|
|
void DisplayListClipState::InvalidateCurrentCombinedClipChain(
|
|
const ActiveScrolledRoot* aInvalidateUpTo) {
|
|
mClippedToDisplayPort = false;
|
|
mCurrentCombinedClipChainIsValid = false;
|
|
while (mCurrentCombinedClipChain &&
|
|
ActiveScrolledRoot::IsAncestor(aInvalidateUpTo,
|
|
mCurrentCombinedClipChain->mASR)) {
|
|
mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent;
|
|
}
|
|
}
|
|
|
|
void DisplayListClipState::ClipContainingBlockDescendantsToContentBox(
|
|
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
|
DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags) {
|
|
nscoord radii[8];
|
|
bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii);
|
|
if (!hasBorderRadius &&
|
|
(aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) {
|
|
return;
|
|
}
|
|
|
|
nsRect clipRect = aFrame->GetContentRectRelativeToSelf() +
|
|
aBuilder->ToReferenceFrame(aFrame);
|
|
// If we have a border-radius, we have to clip our content to that
|
|
// radius.
|
|
ClipContainingBlockDescendants(
|
|
aBuilder, clipRect, hasBorderRadius ? radii : nullptr, aClipChainOnStack);
|
|
}
|
|
|
|
DisplayListClipState::AutoSaveRestore::AutoSaveRestore(
|
|
nsDisplayListBuilder* aBuilder)
|
|
: mBuilder(aBuilder),
|
|
mState(aBuilder->ClipState()),
|
|
mSavedState(aBuilder->ClipState())
|
|
#ifdef DEBUG
|
|
,
|
|
mClipUsed(false),
|
|
mRestored(false)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
} // namespace mozilla
|