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/. */
7 #include "DisplayListClipState.h"
9 #include "nsDisplayList.h"
13 const DisplayItemClipChain
* DisplayListClipState::GetCurrentCombinedClipChain(
14 nsDisplayListBuilder
* aBuilder
) {
15 if (mCurrentCombinedClipChainIsValid
) {
16 return mCurrentCombinedClipChain
;
18 if (!mClipChainContentDescendants
&& !mClipChainContainingBlockDescendants
) {
19 mCurrentCombinedClipChain
= nullptr;
20 mCurrentCombinedClipChainIsValid
= true;
24 mCurrentCombinedClipChain
= aBuilder
->CreateClipChainIntersection(
25 mCurrentCombinedClipChain
, mClipChainContentDescendants
,
26 mClipChainContainingBlockDescendants
);
27 mCurrentCombinedClipChainIsValid
= true;
28 return mCurrentCombinedClipChain
;
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
;
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
;
55 ActiveScrolledRoot::IsAncestor(aASR
, ancestorSC
->mASR
)) {
56 ancestorSC
= ancestorSC
->mParent
;
58 ancestorSC
= aBuilder
->CopyWholeChain(ancestorSC
);
59 aClipChainOnStack
.mParent
= nullptr;
60 aClipToModify
= aBuilder
->CreateClipChainIntersection(
61 ancestorSC
, aClipToModify
, &aClipChainOnStack
);
65 void DisplayListClipState::ClipContainingBlockDescendants(
66 nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
, const nscoord
* aRadii
,
67 DisplayItemClipChain
& aClipChainOnStack
) {
69 aClipChainOnStack
.mClip
.SetTo(aRect
, aRadii
);
71 aClipChainOnStack
.mClip
.SetTo(aRect
);
73 const ActiveScrolledRoot
* asr
= aBuilder
->CurrentActiveScrolledRoot();
74 ApplyClip(aBuilder
, mClipChainContainingBlockDescendants
, asr
,
76 InvalidateCurrentCombinedClipChain(asr
);
79 void DisplayListClipState::ClipContentDescendants(
80 nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
, const nscoord
* aRadii
,
81 DisplayItemClipChain
& aClipChainOnStack
) {
83 aClipChainOnStack
.mClip
.SetTo(aRect
, aRadii
);
85 aClipChainOnStack
.mClip
.SetTo(aRect
);
87 const ActiveScrolledRoot
* asr
= aBuilder
->CurrentActiveScrolledRoot();
88 ApplyClip(aBuilder
, mClipChainContentDescendants
, asr
, aClipChainOnStack
);
89 InvalidateCurrentCombinedClipChain(asr
);
92 void DisplayListClipState::ClipContentDescendants(
93 nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
94 const nsRect
& aRoundedRect
, const nscoord
* aRadii
,
95 DisplayItemClipChain
& aClipChainOnStack
) {
97 aClipChainOnStack
.mClip
.SetTo(aRect
, aRoundedRect
, aRadii
);
99 nsRect intersect
= aRect
.Intersect(aRoundedRect
);
100 aClipChainOnStack
.mClip
.SetTo(intersect
);
102 const ActiveScrolledRoot
* asr
= aBuilder
->CurrentActiveScrolledRoot();
103 ApplyClip(aBuilder
, mClipChainContentDescendants
, asr
, aClipChainOnStack
);
104 InvalidateCurrentCombinedClipChain(asr
);
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
;
118 void DisplayListClipState::ClipContainingBlockDescendantsToContentBox(
119 nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
120 DisplayItemClipChain
& aClipChainOnStack
, uint32_t aFlags
) {
122 bool hasBorderRadius
= aFrame
->GetContentBoxBorderRadii(radii
);
123 if (!hasBorderRadius
&&
124 (aFlags
& ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT
)) {
128 nsRect clipRect
= aFrame
->GetContentRectRelativeToSelf() +
129 aBuilder
->ToReferenceFrame(aFrame
);
130 // If we have a border-radius, we have to clip our content to that
132 ClipContainingBlockDescendants(
133 aBuilder
, clipRect
, hasBorderRadius
? radii
: nullptr, aClipChainOnStack
);
136 DisplayListClipState::AutoSaveRestore::AutoSaveRestore(
137 nsDisplayListBuilder
* aBuilder
)
138 : mBuilder(aBuilder
),
139 mState(aBuilder
->ClipState()),
140 mSavedState(aBuilder
->ClipState())
149 } // namespace mozilla