diff options
Diffstat (limited to 'layout/painting/DisplayListClipState.cpp')
-rw-r--r-- | layout/painting/DisplayListClipState.cpp | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/layout/painting/DisplayListClipState.cpp b/layout/painting/DisplayListClipState.cpp new file mode 100644 index 0000000000..8a87e2906b --- /dev/null +++ b/layout/painting/DisplayListClipState.cpp @@ -0,0 +1,149 @@ +/* -*- 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 |