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 "nsDisplayList.h"
10 
11 namespace mozilla {
12 
GetCurrentCombinedClipChain(nsDisplayListBuilder * aBuilder)13 const DisplayItemClipChain* DisplayListClipState::GetCurrentCombinedClipChain(
14     nsDisplayListBuilder* aBuilder) {
15   if (mCurrentCombinedClipChainIsValid) {
16     return mCurrentCombinedClipChain;
17   }
18   if (!mClipChainContentDescendants && !mClipChainContainingBlockDescendants) {
19     mCurrentCombinedClipChain = nullptr;
20     mCurrentCombinedClipChainIsValid = true;
21     return nullptr;
22   }
23 
24   mCurrentCombinedClipChain = aBuilder->CreateClipChainIntersection(
25       mCurrentCombinedClipChain, mClipChainContentDescendants,
26       mClipChainContainingBlockDescendants);
27   mCurrentCombinedClipChainIsValid = true;
28   return mCurrentCombinedClipChain;
29 }
30 
ApplyClip(nsDisplayListBuilder * aBuilder,const DisplayItemClipChain * & aClipToModify,const ActiveScrolledRoot * aASR,DisplayItemClipChain & aClipChainOnStack)31 static void ApplyClip(nsDisplayListBuilder* aBuilder,
32                       const DisplayItemClipChain*& aClipToModify,
33                       const ActiveScrolledRoot* aASR,
34                       DisplayItemClipChain& aClipChainOnStack) {
35   aClipChainOnStack.mASR = aASR;
36   if (aClipToModify && aClipToModify->mASR == aASR) {
37     // Intersect with aClipToModify and replace the clip chain item.
38     aClipChainOnStack.mClip.IntersectWith(aClipToModify->mClip);
39     aClipChainOnStack.mParent = aClipToModify->mParent;
40     aClipToModify = &aClipChainOnStack;
41   } else if (!aClipToModify ||
42              ActiveScrolledRoot::IsAncestor(aClipToModify->mASR, aASR)) {
43     // Add a new clip chain item at the bottom.
44     aClipChainOnStack.mParent = aClipToModify;
45     aClipToModify = &aClipChainOnStack;
46   } else {
47     // We need to insert / intersect a DisplayItemClipChain in the middle of the
48     // aClipToModify chain. This is a very rare case.
49     // Find the common ancestor and have the builder create the
50     // DisplayItemClipChain intersection. This will create new
51     // DisplayItemClipChain objects for all descendants of ancestorSC and we
52     // will not hold on to a pointer to aClipChainOnStack.
53     const DisplayItemClipChain* ancestorSC = aClipToModify;
54     while (ancestorSC &&
55            ActiveScrolledRoot::IsAncestor(aASR, ancestorSC->mASR)) {
56       ancestorSC = ancestorSC->mParent;
57     }
58     ancestorSC = aBuilder->CopyWholeChain(ancestorSC);
59     aClipChainOnStack.mParent = nullptr;
60     aClipToModify = aBuilder->CreateClipChainIntersection(
61         ancestorSC, aClipToModify, &aClipChainOnStack);
62   }
63 }
64 
ClipContainingBlockDescendants(nsDisplayListBuilder * aBuilder,const nsRect & aRect,const nscoord * aRadii,DisplayItemClipChain & aClipChainOnStack)65 void DisplayListClipState::ClipContainingBlockDescendants(
66     nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
67     DisplayItemClipChain& aClipChainOnStack) {
68   if (aRadii) {
69     aClipChainOnStack.mClip.SetTo(aRect, aRadii);
70   } else {
71     aClipChainOnStack.mClip.SetTo(aRect);
72   }
73   const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
74   ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr,
75             aClipChainOnStack);
76   InvalidateCurrentCombinedClipChain(asr);
77 }
78 
ClipContentDescendants(nsDisplayListBuilder * aBuilder,const nsRect & aRect,const nscoord * aRadii,DisplayItemClipChain & aClipChainOnStack)79 void DisplayListClipState::ClipContentDescendants(
80     nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
81     DisplayItemClipChain& aClipChainOnStack) {
82   if (aRadii) {
83     aClipChainOnStack.mClip.SetTo(aRect, aRadii);
84   } else {
85     aClipChainOnStack.mClip.SetTo(aRect);
86   }
87   const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
88   ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
89   InvalidateCurrentCombinedClipChain(asr);
90 }
91 
ClipContentDescendants(nsDisplayListBuilder * aBuilder,const nsRect & aRect,const nsRect & aRoundedRect,const nscoord * aRadii,DisplayItemClipChain & aClipChainOnStack)92 void DisplayListClipState::ClipContentDescendants(
93     nsDisplayListBuilder* aBuilder, const nsRect& aRect,
94     const nsRect& aRoundedRect, const nscoord* aRadii,
95     DisplayItemClipChain& aClipChainOnStack) {
96   if (aRadii) {
97     aClipChainOnStack.mClip.SetTo(aRect, aRoundedRect, aRadii);
98   } else {
99     nsRect intersect = aRect.Intersect(aRoundedRect);
100     aClipChainOnStack.mClip.SetTo(intersect);
101   }
102   const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
103   ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
104   InvalidateCurrentCombinedClipChain(asr);
105 }
106 
InvalidateCurrentCombinedClipChain(const ActiveScrolledRoot * aInvalidateUpTo)107 void DisplayListClipState::InvalidateCurrentCombinedClipChain(
108     const ActiveScrolledRoot* aInvalidateUpTo) {
109   mCurrentCombinedClipChainIsValid = false;
110   while (mCurrentCombinedClipChain &&
111          ActiveScrolledRoot::IsAncestor(aInvalidateUpTo,
112                                         mCurrentCombinedClipChain->mASR)) {
113     mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent;
114   }
115 }
116 
ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,DisplayItemClipChain & aClipChainOnStack,uint32_t aFlags)117 void DisplayListClipState::ClipContainingBlockDescendantsToContentBox(
118     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
119     DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags) {
120   nscoord radii[8];
121   bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii);
122   if (!hasBorderRadius &&
123       (aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) {
124     return;
125   }
126 
127   nsRect clipRect = aFrame->GetContentRectRelativeToSelf() +
128                     aBuilder->ToReferenceFrame(aFrame);
129   // If we have a border-radius, we have to clip our content to that
130   // radius.
131   ClipContainingBlockDescendants(
132       aBuilder, clipRect, hasBorderRadius ? radii : nullptr, aClipChainOnStack);
133 }
134 
AutoSaveRestore(nsDisplayListBuilder * aBuilder)135 DisplayListClipState::AutoSaveRestore::AutoSaveRestore(
136     nsDisplayListBuilder* aBuilder)
137     : mBuilder(aBuilder),
138       mState(aBuilder->ClipState()),
139       mSavedState(aBuilder->ClipState())
140 #ifdef DEBUG
141       ,
142       mClipUsed(false),
143       mRestored(false)
144 #endif
145 {
146 }
147 
148 }  // namespace mozilla
149