DisplayListClipState.cpp (6546B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "DisplayListClipState.h" 8 9 #include "DisplayItemClipChain.h" 10 #include "nsDisplayList.h" 11 12 namespace mozilla { 13 14 const DisplayItemClipChain* DisplayListClipState::GetCurrentCombinedClipChain( 15 nsDisplayListBuilder* aBuilder) { 16 if (mCurrentCombinedClipChainIsValid) { 17 return mCurrentCombinedClipChain; 18 } 19 if (!mClipChainContentDescendants && !mClipChainContainingBlockDescendants) { 20 mCurrentCombinedClipChain = nullptr; 21 mCurrentCombinedClipChainIsValid = true; 22 return nullptr; 23 } 24 25 mCurrentCombinedClipChain = aBuilder->CreateClipChainIntersection( 26 mCurrentCombinedClipChain, mClipChainContentDescendants, 27 mClipChainContainingBlockDescendants); 28 mCurrentCombinedClipChainIsValid = true; 29 return mCurrentCombinedClipChain; 30 } 31 32 static void ApplyClip(nsDisplayListBuilder* aBuilder, 33 const DisplayItemClipChain*& aClipToModify, 34 const ActiveScrolledRoot* aASR, 35 DisplayItemClipChain& aClipChainOnStack) { 36 aClipChainOnStack.mASR = aASR; 37 if (aClipToModify && aClipToModify->mASR == aASR && 38 !aClipChainOnStack.IsDisplayportClip()) { 39 // Intersect with aClipToModify and replace the clip chain item. 40 // Do not apply this optimization to displayport clips, because it would 41 // break our ability to skip them in MaybeRemoveDisplayportClip(). 42 aClipChainOnStack.mClip.IntersectWith(aClipToModify->mClip); 43 aClipChainOnStack.mParent = aClipToModify->mParent; 44 aClipToModify = &aClipChainOnStack; 45 } else if (!aClipToModify || 46 ActiveScrolledRoot::IsAncestor(aClipToModify->mASR, aASR)) { 47 // Add a new clip chain item at the bottom. 48 aClipChainOnStack.mParent = aClipToModify; 49 aClipToModify = &aClipChainOnStack; 50 } else { 51 // We need to insert / intersect a DisplayItemClipChain in the middle of the 52 // aClipToModify chain. This is a very rare case. 53 // Find the common ancestor and have the builder create the 54 // DisplayItemClipChain intersection. This will create new 55 // DisplayItemClipChain objects for all descendants of ancestorSC and we 56 // will not hold on to a pointer to aClipChainOnStack. 57 const DisplayItemClipChain* ancestorSC = aClipToModify; 58 while (ancestorSC && 59 ActiveScrolledRoot::IsAncestor(aASR, ancestorSC->mASR)) { 60 ancestorSC = ancestorSC->mParent; 61 } 62 ancestorSC = aBuilder->CopyWholeChain(ancestorSC); 63 aClipChainOnStack.mParent = nullptr; 64 aClipToModify = aBuilder->CreateClipChainIntersection( 65 ancestorSC, aClipToModify, &aClipChainOnStack); 66 } 67 } 68 69 void DisplayListClipState::ClipContainingBlockDescendants( 70 nsDisplayListBuilder* aBuilder, const nsRect& aRect, 71 const nsRectCornerRadii* aRadii, DisplayItemClipChain& aClipChainOnStack) { 72 if (aRadii) { 73 aClipChainOnStack.mClip.SetTo(aRect, aRadii); 74 } else { 75 aClipChainOnStack.mClip.SetTo(aRect); 76 } 77 const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot(); 78 ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr, 79 aClipChainOnStack); 80 InvalidateCurrentCombinedClipChain(asr); 81 } 82 83 void DisplayListClipState::ClipToDisplayPort( 84 nsDisplayListBuilder* aBuilder, const nsRect& aRect, 85 DisplayItemClipChain& aClipChainOnStack) { 86 aClipChainOnStack.mClip.SetTo(aRect); 87 aClipChainOnStack.mKind = DisplayItemClipChain::ClipKind::Displayport; 88 const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot(); 89 ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr, 90 aClipChainOnStack); 91 InvalidateCurrentCombinedClipChain(asr); 92 } 93 94 void DisplayListClipState::ClipContentDescendants( 95 nsDisplayListBuilder* aBuilder, const nsRect& aRect, 96 const nsRectCornerRadii* aRadii, DisplayItemClipChain& aClipChainOnStack) { 97 if (aRadii) { 98 aClipChainOnStack.mClip.SetTo(aRect, aRadii); 99 } else { 100 aClipChainOnStack.mClip.SetTo(aRect); 101 } 102 const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot(); 103 ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack); 104 InvalidateCurrentCombinedClipChain(asr); 105 } 106 107 void DisplayListClipState::ClipContentDescendants( 108 nsDisplayListBuilder* aBuilder, const nsRect& aRect, 109 const nsRect& aRoundedRect, const nsRectCornerRadii* aRadii, 110 DisplayItemClipChain& aClipChainOnStack) { 111 if (aRadii) { 112 aClipChainOnStack.mClip.SetTo(aRect, aRoundedRect, aRadii); 113 } else { 114 nsRect intersect = aRect.Intersect(aRoundedRect); 115 aClipChainOnStack.mClip.SetTo(intersect); 116 } 117 const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot(); 118 ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack); 119 InvalidateCurrentCombinedClipChain(asr); 120 } 121 122 void DisplayListClipState::InvalidateCurrentCombinedClipChain( 123 const ActiveScrolledRoot* aInvalidateUpTo) { 124 mClippedToDisplayPort = false; 125 mCurrentCombinedClipChainIsValid = false; 126 while (mCurrentCombinedClipChain && 127 ActiveScrolledRoot::IsAncestor(aInvalidateUpTo, 128 mCurrentCombinedClipChain->mASR)) { 129 mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent; 130 } 131 } 132 133 void DisplayListClipState::ClipContainingBlockDescendantsToContentBox( 134 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, 135 DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags) { 136 nsRectCornerRadii radii; 137 bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii); 138 if (!hasBorderRadius && 139 (aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) { 140 return; 141 } 142 143 nsRect clipRect = aFrame->GetContentRectRelativeToSelf() + 144 aBuilder->ToReferenceFrame(aFrame); 145 // If we have a border-radius, we have to clip our content to that 146 // radius. 147 ClipContainingBlockDescendants(aBuilder, clipRect, 148 hasBorderRadius ? &radii : nullptr, 149 aClipChainOnStack); 150 } 151 152 DisplayListClipState::AutoSaveRestore::AutoSaveRestore( 153 nsDisplayListBuilder* aBuilder) 154 : mBuilder(aBuilder), 155 mState(aBuilder->ClipState()), 156 mSavedState(aBuilder->ClipState()) 157 #ifdef DEBUG 158 , 159 mClipUsed(false), 160 mRestored(false) 161 #endif 162 { 163 } 164 165 } // namespace mozilla