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 mClippedToDisplayPort = false;
110 mCurrentCombinedClipChainIsValid = false;
111 while (mCurrentCombinedClipChain &&
112 ActiveScrolledRoot::IsAncestor(aInvalidateUpTo,
113 mCurrentCombinedClipChain->mASR)) {
114 mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent;
115 }
116 }
117
ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,DisplayItemClipChain & aClipChainOnStack,uint32_t aFlags)118 void DisplayListClipState::ClipContainingBlockDescendantsToContentBox(
119 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
120 DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags) {
121 nscoord radii[8];
122 bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii);
123 if (!hasBorderRadius &&
124 (aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) {
125 return;
126 }
127
128 nsRect clipRect = aFrame->GetContentRectRelativeToSelf() +
129 aBuilder->ToReferenceFrame(aFrame);
130 // If we have a border-radius, we have to clip our content to that
131 // radius.
132 ClipContainingBlockDescendants(
133 aBuilder, clipRect, hasBorderRadius ? radii : nullptr, aClipChainOnStack);
134 }
135
AutoSaveRestore(nsDisplayListBuilder * aBuilder)136 DisplayListClipState::AutoSaveRestore::AutoSaveRestore(
137 nsDisplayListBuilder* aBuilder)
138 : mBuilder(aBuilder),
139 mState(aBuilder->ClipState()),
140 mSavedState(aBuilder->ClipState())
141 #ifdef DEBUG
142 ,
143 mClipUsed(false),
144 mRestored(false)
145 #endif
146 {
147 }
148
149 } // namespace mozilla
150