|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef DISPLAYLISTCLIPSTATE_H_ |
|
7 #define DISPLAYLISTCLIPSTATE_H_ |
|
8 |
|
9 #include "DisplayItemClip.h" |
|
10 |
|
11 #include "mozilla/DebugOnly.h" |
|
12 |
|
13 class nsIFrame; |
|
14 class nsDisplayListBuilder; |
|
15 |
|
16 namespace mozilla { |
|
17 |
|
18 /** |
|
19 * All clip coordinates are in appunits relative to the reference frame |
|
20 * for the display item we're building. |
|
21 */ |
|
22 class DisplayListClipState { |
|
23 public: |
|
24 DisplayListClipState() |
|
25 : mClipContentDescendants(nullptr) |
|
26 , mClipContainingBlockDescendants(nullptr) |
|
27 , mCurrentCombinedClip(nullptr) |
|
28 {} |
|
29 |
|
30 /** |
|
31 * Returns intersection of mClipContainingBlockDescendants and |
|
32 * mClipContentDescendants, allocated on aBuilder's arena. |
|
33 */ |
|
34 const DisplayItemClip* GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder); |
|
35 |
|
36 const DisplayItemClip* GetClipForContainingBlockDescendants() const |
|
37 { |
|
38 return mClipContainingBlockDescendants; |
|
39 } |
|
40 const DisplayItemClip* GetClipForContentDescendants() const |
|
41 { |
|
42 return mClipContentDescendants; |
|
43 } |
|
44 |
|
45 class AutoSaveRestore; |
|
46 friend class AutoSaveRestore; |
|
47 |
|
48 class AutoClipContainingBlockDescendantsToContentBox; |
|
49 friend class AutoClipContainingBlockDescendantsToContentBox; |
|
50 |
|
51 class AutoClipMultiple; |
|
52 friend class AutoClipMultiple; |
|
53 |
|
54 enum { |
|
55 ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01 |
|
56 }; |
|
57 |
|
58 private: |
|
59 void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) |
|
60 { |
|
61 mClipContainingBlockDescendants = aClip; |
|
62 mCurrentCombinedClip = nullptr; |
|
63 } |
|
64 |
|
65 void Clear() |
|
66 { |
|
67 mClipContentDescendants = nullptr; |
|
68 mClipContainingBlockDescendants = nullptr; |
|
69 mCurrentCombinedClip = nullptr; |
|
70 } |
|
71 |
|
72 /** |
|
73 * Intersects the given clip rect (with optional aRadii) with the current |
|
74 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to |
|
75 * the result, stored in aClipOnStack. |
|
76 */ |
|
77 void ClipContainingBlockDescendants(const nsRect& aRect, |
|
78 const nscoord* aRadii, |
|
79 DisplayItemClip& aClipOnStack); |
|
80 |
|
81 void ClipContentDescendants(const nsRect& aRect, |
|
82 const nscoord* aRadii, |
|
83 DisplayItemClip& aClipOnStack); |
|
84 |
|
85 /** |
|
86 * Clips containing-block descendants to the frame's content-box, |
|
87 * taking border-radius into account. |
|
88 * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then |
|
89 * we assume display items will not draw outside the content rect, so |
|
90 * clipping is only required if there is a border-radius. This is an |
|
91 * optimization to reduce the amount of clipping required. |
|
92 */ |
|
93 void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, |
|
94 nsIFrame* aFrame, |
|
95 DisplayItemClip& aClipOnStack, |
|
96 uint32_t aFlags); |
|
97 |
|
98 /** |
|
99 * All content descendants (i.e. following placeholder frames to their |
|
100 * out-of-flows if necessary) should be clipped by mClipContentDescendants. |
|
101 * Null if no clipping applies. |
|
102 */ |
|
103 const DisplayItemClip* mClipContentDescendants; |
|
104 /** |
|
105 * All containing-block descendants (i.e. frame descendants), including |
|
106 * display items for the current frame, should be clipped by |
|
107 * mClipContainingBlockDescendants. |
|
108 * Null if no clipping applies. |
|
109 */ |
|
110 const DisplayItemClip* mClipContainingBlockDescendants; |
|
111 /** |
|
112 * The intersection of mClipContentDescendants and |
|
113 * mClipContainingBlockDescendants. |
|
114 * Allocated in the nsDisplayListBuilder arena. Null if none has been |
|
115 * allocated or both mClipContentDescendants and mClipContainingBlockDescendants |
|
116 * are null. |
|
117 */ |
|
118 const DisplayItemClip* mCurrentCombinedClip; |
|
119 }; |
|
120 |
|
121 /** |
|
122 * A class to automatically save and restore the current clip state. Also |
|
123 * offers methods for modifying the clip state. Only one modification is allowed |
|
124 * to be in scope at a time using one of these objects; multiple modifications |
|
125 * require nested objects. The interface is written this way to prevent |
|
126 * dangling pointers to DisplayItemClips. |
|
127 */ |
|
128 class DisplayListClipState::AutoSaveRestore { |
|
129 public: |
|
130 AutoSaveRestore(nsDisplayListBuilder* aBuilder); |
|
131 void Restore() |
|
132 { |
|
133 mState = mSavedState; |
|
134 mRestored = true; |
|
135 } |
|
136 ~AutoSaveRestore() |
|
137 { |
|
138 mState = mSavedState; |
|
139 } |
|
140 |
|
141 void Clear() |
|
142 { |
|
143 NS_ASSERTION(!mRestored, "Already restored!"); |
|
144 mState.Clear(); |
|
145 mClipUsed = false; |
|
146 } |
|
147 |
|
148 /** |
|
149 * Intersects the given clip rect (with optional aRadii) with the current |
|
150 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to |
|
151 * the result, stored in aClipOnStack. |
|
152 */ |
|
153 void ClipContainingBlockDescendants(const nsRect& aRect, |
|
154 const nscoord* aRadii = nullptr) |
|
155 { |
|
156 NS_ASSERTION(!mRestored, "Already restored!"); |
|
157 NS_ASSERTION(!mClipUsed, "mClip already used"); |
|
158 mClipUsed = true; |
|
159 mState.ClipContainingBlockDescendants(aRect, aRadii, mClip); |
|
160 } |
|
161 |
|
162 void ClipContentDescendants(const nsRect& aRect, |
|
163 const nscoord* aRadii = nullptr) |
|
164 { |
|
165 NS_ASSERTION(!mRestored, "Already restored!"); |
|
166 NS_ASSERTION(!mClipUsed, "mClip already used"); |
|
167 mClipUsed = true; |
|
168 mState.ClipContentDescendants(aRect, aRadii, mClip); |
|
169 } |
|
170 |
|
171 /** |
|
172 * Clips containing-block descendants to the frame's content-box, |
|
173 * taking border-radius into account. |
|
174 * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then |
|
175 * we assume display items will not draw outside the content rect, so |
|
176 * clipping is only required if there is a border-radius. This is an |
|
177 * optimization to reduce the amount of clipping required. |
|
178 */ |
|
179 void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, |
|
180 nsIFrame* aFrame, |
|
181 uint32_t aFlags = 0) |
|
182 { |
|
183 NS_ASSERTION(!mRestored, "Already restored!"); |
|
184 NS_ASSERTION(!mClipUsed, "mClip already used"); |
|
185 mClipUsed = true; |
|
186 mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); |
|
187 } |
|
188 |
|
189 protected: |
|
190 DisplayListClipState& mState; |
|
191 DisplayListClipState mSavedState; |
|
192 DisplayItemClip mClip; |
|
193 DebugOnly<bool> mClipUsed; |
|
194 DebugOnly<bool> mRestored; |
|
195 }; |
|
196 |
|
197 class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox : public AutoSaveRestore { |
|
198 public: |
|
199 AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, |
|
200 nsIFrame* aFrame, |
|
201 uint32_t aFlags = 0) |
|
202 : AutoSaveRestore(aBuilder) |
|
203 { |
|
204 mClipUsed = true; |
|
205 mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); |
|
206 } |
|
207 }; |
|
208 |
|
209 /** |
|
210 * Do not use this outside of nsFrame::BuildDisplayListForChild, use |
|
211 * multiple AutoSaveRestores instead. We provide this class just to ensure |
|
212 * BuildDisplayListForChild is as efficient as possible. |
|
213 */ |
|
214 class DisplayListClipState::AutoClipMultiple : public AutoSaveRestore { |
|
215 public: |
|
216 AutoClipMultiple(nsDisplayListBuilder* aBuilder) |
|
217 : AutoSaveRestore(aBuilder) |
|
218 , mExtraClipUsed(false) |
|
219 {} |
|
220 |
|
221 /** |
|
222 * *aClip must survive longer than this object. Be careful!!! |
|
223 */ |
|
224 void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) |
|
225 { |
|
226 mState.SetClipForContainingBlockDescendants(aClip); |
|
227 } |
|
228 |
|
229 /** |
|
230 * Intersects the given clip rect (with optional aRadii) with the current |
|
231 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to |
|
232 * the result, stored in aClipOnStack. |
|
233 */ |
|
234 void ClipContainingBlockDescendantsExtra(const nsRect& aRect, |
|
235 const nscoord* aRadii) |
|
236 { |
|
237 NS_ASSERTION(!mRestored, "Already restored!"); |
|
238 NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used"); |
|
239 mExtraClipUsed = true; |
|
240 mState.ClipContainingBlockDescendants(aRect, aRadii, mExtraClip); |
|
241 } |
|
242 |
|
243 protected: |
|
244 DisplayItemClip mExtraClip; |
|
245 DebugOnly<bool> mExtraClipUsed; |
|
246 }; |
|
247 |
|
248 } |
|
249 |
|
250 #endif /* DISPLAYLISTCLIPSTATE_H_ */ |